本篇将涉及,通过本篇可以对整个springmvc模块有一个清晰的视角,在日常开发中可以快速定位问题和源码
主要完成以下工作:
主要完成以下工作:
在这一步中,分为两个阶段:
先来看一下其类关系图
SourceFilteringListener作为EventListener的实现类,在servlet的ApplicationContext初始化后,将收到事件回调完成剩余的初始化工作
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
在这些初始化方法中,注册到spring容器中的bean由注解@EnableWebMVC导入。
导入工作委托给了DelegatingWebMvcConfiguration类
以上就是springMVC的初始化过程的整体脉络
整个过程相对比较复杂,整个逻辑在DispatcherServlet#doDispatcher方法中实现,该方法内部将具体工作委托给了RequestMappingHandlerMapping、HandlerExcutionChain、RequestMappingHandlerAdapter、ViewResolver、View等几个核心类来完成任务。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
// 获取HandlerExcutionChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 获取HandlerAdapter
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
// 调用拦截器前置处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 真正调用HandlerMethod(即Controller方法),内部涉及了参数解析(处理@RequestParams、@PathVariables注解原理)、参数类型转换、HandlerMethod执行结果处理(@ResponseBody注解原理)这几个步骤。后面内容我们详细剖析这个函数的内部机制
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
// 调用拦截器后置处理
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
// 处理结果,涉及到视图渲染
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
具体寻找过程的代码细节如下:
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
// 如果没有找到,则遍历所有Controller方法。这里会涉及到Ant风格解析。O(n)的时间复杂度。效率极低
// 在使用路径参数@PathVariables的时候,会进入到这段逻辑
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
// 设置属性到ServletHttpRequest实例中,在解析@PathVariables时使用
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
super.handleMatch(info, lookupPath, request);
String bestPattern;
Map<String, String> uriVariables;
Map<String, String> decodedUriVariables;
Set<String> patterns = info.getPatternsCondition().getPatterns();
if (patterns.isEmpty()) {
bestPattern = lookupPath;
uriVariables = Collections.emptyMap();
decodedUriVariables = Collections.emptyMap();
}
else {
bestPattern = patterns.iterator().next();
// 使用Ant风格解析路径参数
uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
decodedUriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
}
request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedUriVariables);
if (isMatrixVariableContentAvailable()) {
Map<String, MultiValueMap<String, String>> matrixVars = extractMatrixVariables(request, uriVariables);
request.setAttribute(HandlerMapping.MATRIX_VARIABLES_ATTRIBUTE, matrixVars);
}
if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
}
}
主要是通过HandlerMethodArgumentResolverComposite这个特殊的HandlerMethodArgumentResolver聚合了多个HandlerMethodArgumentResolver来解析参数、其内部将调用RequestParamMethodArgumentResolver、PathVariableMapMethodArgumentResolver等来处理参数解析逻辑
主要是通过HandlerMethodReturnValueHandlerComposite这个特殊的HandlerMethodReturnValueHandler聚合了多个HandlerMethodReturnValueHandler来处理返回结果,其内部将调用RequestResponseBodyMethodProcessor处理@ResponseBody、@RestController标记的方法和类来完成RESTful接口的结果返回
以上就是整个springmvc的工作流程,包括了初始化、请求处理两个步骤。在请求处理的过程中又涉及到了参数解析、参数类型转换、返回结果处理这些流程。由于整个代码比较繁多,这里就不列举所有的流程(视图渲染、异常处理这些细节)通过本篇的主体流程图可以快速定位到具体的代码。后续有需要查看更多细节可参考本篇快速定位