SpringMVC——DispatcherServlet
tomcat容器启动加载web.xml初始化springmvc相关策略组件
一、WebApplicationContext的层次结构
本来是想研究一下springMVC组件的,结果解决了以前的一个疑问。WebApplicationContext的层次结构
下面是从官网copy的一份web.xml
ContextLoaderListener:初始化一个Root WebApplicationContext:SpringIOC初始化一些中间services+datasouces的Bean
DispatcherServlet:初始化一个Servlet WebApplicationContext:SpringIOC初始化前端controllers+view resovlers+HandleMapping的Bean
父子关系:Servlet WebApplicationContext.setParent(Root WebApplicationContext);子容器找不到就去父容器找。
<web-app> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-context.xml</param-value> </context-param> <servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/app/*</url-pattern> </servlet-mapping> </web-app>
二、DispatcherServlet初始化(Servlet生命周期init())
servlet.init()时初始化SpringIOC容器外,还有初始化了一部分SpringMVC组件
/* org.springframework.web.servlet.DispatcherServlet#initStrategies */ protected void initStrategies(ApplicationContext context) { //多路解析器 文件上传 HttpServletRequest-->MultipartHttpServletRequest initMultipartResolver(context); //国际化 initLocaleResolver(context); //主题 initThemeResolver(context); //初始化HandleMapping容器 initHandlerMappings(context); //初始化HandlerAdapters容器 initHandlerAdapters(context); //初始化HandlerExceptionResolver容器 initHandlerExceptionResolvers(context); //Request转viewName initRequestToViewNameTranslator(context); //初始化视图解析器 initViewResolvers(context); //初始化FlashMapManager initFlashMapManager(context); }
重点看下HandlerMapping与HandlerAdapters
1、HandlerMapping:初始化mapping+拦截器interceptors
initHandlerMappings(context):初始化HandlerMapping,
/* org.springframework.web.servlet.DispatcherServlet#initHandlerMappings */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) {//从ioc容器中获取显式设置(xml或者注解)的HandlerMapping类型的Bean //根据类型到 Servlet applicationContex及Root applicationContext中去查找 //一般情况下,在项目中是不会显式的配置HandlerMapping类型的Bean的 //所以这里会返回null Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } if (this.handlerMappings == null) { //由于没有显式的配置HandlerMapping的Bean //此时会默认初始化从DispatcherServlet.properties中设定的3个HandlerMapping的Bean //org/springframework/web/servlet/DispatcherServlet.properties // ① org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping // ② springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping // ③ org.springframework.web.servlet.function.support.RouterFunctionMapping this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isTraceEnabled()) { logger.trace("No HandlerMappings declared for servlet '" + getServletName() + "': using default strategies from DispatcherServlet.properties"); } } }
DispatchServlet.properties 注意标红的Bean,很眼熟
/* org/springframework/web/servlet/DispatcherServlet.properties */ /* 没有显式设置组件时,DispatcherServlet会默认初始化下面类型的Bean到容器中 * MultijpartResolve没有默认,需要显式设置 */ //国际化 org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver //主题 org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver //HandlerMapping org.springframework.web.servlet.HandlerMapping=
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\ org.springframework.web.servlet.function.support.RouterFunctionMapping //handlerAdapter org.springframework.web.servlet.HandlerAdapter=
org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\ org.springframework.web.servlet.function.support.HandlerFunctionAdapter //HandlerExceptionResolve org.springframework.web.servlet.HandlerExceptionResolver= org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver //RequestToViewNameTranslator org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator //ViewResolver org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver //FlashMapManager org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
RequestHandlerRequestMapping:请求uri到controller方法的映射器
打断点发现RequestHandlerRequestMapping初始化后就已经存在映射关系,
① 然后跟踪createBean()最终发现Bean初始化最后阶段调用afterPropertiesSet()时注册映射关系,初始化mapping
/* org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#afterPropertiesSet */ public void afterPropertiesSet() { this.config = new RequestMappingInfo.BuilderConfiguration(); this.config.setUrlPathHelper(getUrlPathHelper()); this.config.setPathMatcher(getPathMatcher()); this.config.setSuffixPatternMatch(useSuffixPatternMatch()); this.config.setTrailingSlashMatch(useTrailingSlashMatch()); this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch()); this.config.setContentNegotiationManager(getContentNegotiationManager()); //注册RequestMapping super.afterPropertiesSet(); } /* org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#afterPropertiesSet */ public void afterPropertiesSet() { initHandlerMethods(); } protected void initHandlerMethods() { //getCandidateBeanNames()获取所有实例化的Bean, //注意:DispatcherServlet.initStrategies()是在IOC容器初始化完成后 for (String beanName : getCandidateBeanNames()) { //过滤scopedTarget.开头的Bean if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { //扫描@Controller或者@RequestMapping注解的类 //扫描@RequestMapping注解的方法 //注册到映射关系到对应容器中(url-RequestMappingInfo) processCandidateBean(beanName); } } //不可修改视图+打印日志 handlerMethodsInitialized(getHandlerMethods()); } protected void processCandidateBean(String beanName) { Class<?> beanType = null; try { //获取beanType beanType = obtainApplicationContext().getType(beanName); } catch (Throwable ex) { // An unresolvable bean type, probably from a lazy bean - let's ignore it. if (logger.isTraceEnabled()) { logger.trace("Could not resolve type for bean '" + beanName + "'", ex); } } //检查beanType不为空 //并且beanType被@Controller或者@RequestMapping注解 if (beanType != null && isHandler(beanType)) { detectHandlerMethods(beanName); } } protected void detectHandlerMethods(Object handler) { //重新获取beanType == handlerType Class<?> handlerType = (handler instanceof String ? obtainApplicationContext().getType((String) handler) : handler.getClass()); if (handlerType != null) { Class<?> userType = ClassUtils.getUserClass(handlerType); //获取映射关系<Method , RequestMappingInfo> Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (MethodIntrospector.MetadataLookup<T>) method -> { try { //selectMethods中查找beanType的所有方法 //然后遍历method,getMappingForMethod获取@RequestMapping信息生成一个RequestMappingInfo实例 //重点RequestMappingInfo.path=Controller的@RequestMapping.value+Method的@RequestMaping.value //然后生成映射关系<method,RequestMappingInfo> return getMappingForMethod(method, userType); } catch (Throwable ex) { throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, ex); } }); if (logger.isTraceEnabled()) { logger.trace(formatMappings(userType, methods)); } //注册映射关系 methods.forEach((method, mapping) -> { Method invocableMethod = AopUtils.selectInvocableMethod(method, userType); //注册映射关系到RequestMapHandlerMapping.mappingRegistry的五个容器中 //mappingRegistry的类型:org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry //5个容器全部是Map类型 //urlLookup.add(url, mapping); //mappingLookup.put(mapping, handlerMethod); //corsLookup.put(handlerMethod, corsConfig); //registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name)); //nameLookup.put(name, newList);newList=List<handlerMethod> //handlerMethod就是beanName、beanType、beanFactory、method、parameters的封装 //其实就是url -> mapping -> handlerMethod ->invoke registerHandlerMethod(handler, invocableMethod, mapping); }); } }
② 初始化拦截器interceptors
其实初始化拦截器还要在初始化mapping之前,回忆一下bean初始化
/* org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition) */ protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) { ... if (mbd == null || !mbd.isSynthetic()) { //调用所有BeanPostProcessor前置方法 //这里初始化拦截器interceptors wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { //调用afterPropertiesSet() 这里 初始化mapping invokeInitMethods(beanName, wrappedBean, mbd); } ... }
调用ApplicaitonContextAwareProcessor.postProcessorBeforeInitialization(),实现拦截器初始化,最终走到下面:
/* org.springframework.web.servlet.handler.AbstractHandlerMapping#initApplicationContext */ protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.adaptedInterceptors); initInterceptors(); }
此时RequestHandlerRequestMapping初始化完成:
2、RequestMappingHandlerAdapter
① 同RequestHandlerRequestMapping一样,也是afterPropertiesSet()方法中完成注册,而且更加直接
public void afterPropertiesSet() { // Do this first, it may add ResponseBody advice beans initControllerAdviceCache(); //参数类型解析器(总共注册了20+个解析器) //重点关注:ServletModelAttributeMethodProcessor,后面会用到 if (this.argumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers(); this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } //参数类型赋值器(总共注册了10+个解析器) if (this.initBinderArgumentResolvers == null) { List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers(); this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers); } //返回参数类型解析器(总共注册了10+个解析器) if (this.returnValueHandlers == null) { List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers(); this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers); } }
三、DispatcherServlet服务(Servlet生命周期servlet.service(request,response))
DispatcherServlet的流程:FrameworkServlet.service()-->httpServlet.service()-->FrameworkServlet.doGet()-->FrameworkServlet.processRequest-->DispatcherServlet.doService()-->DispatcherServlet.doDispatch()
直接从doDispatch()开始:springmvc执行流程。
/* org.springframework.web.servlet.DispatcherServlet#doDispatch */ 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 { //检查是否是文件上传请求 //是则转换为multipartRequest processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 确定当前请求的处理程序 //① 根据request中url确定执行方法methodHandler //② 根据request中url确定拦截器interceptors mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 确定当前请求的处理程序的适配器,通常是RequestMappingHandlerAdapter
// 默认的四个适配器分别匹配 // HttpRequestHandlerAdapter: handler instanceof HttpRequestHandler // SimpleControllerHandlerAdapter:handler instanceof Controller // RequestMappingHandlerAdapter:handler instanceof HandlerMethod // HandlerFunctionAdapter:handler instanceof HandlerFunction 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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } // 执行拦截器前置方法 // interceptor.preHandle // interceptor.preHandle没通过调用interceptor.afterCompletion然后直接返回 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 实例调用程序,mappedHandler.getHandlder == MethodHandler即已经可以找到执行的controller和执行的method
// Adapter发挥作用的地方request.parameter转化为method的参数类型 // 然后执行方法 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //viewNameTranslator applyDefaultViewName(processedRequest, mv); //拦截器后置方法 //interceptor.postHandle 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); } // handlerExceptionResolvers //异常会执行interceptor.afterCompletion processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //异常会执行interceptor.afterCompletion triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { //异常会执行interceptor.afterCompletion triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion // 异步处理时,用interceptor释放资源 // AsyncHandlerInterceptor.afterConcurrentHandlingStarted if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { //清除multipartResolver使用的所有资源 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
mv = ha.handle(processedRequest, response, mappedHandler.getHandler()):实际controller.method调用
AbstractHandlerMethodAdapter.handle()-->RequestMappingHandlerAdapter.handleInternal()-->RequestMappingHandlerAdapter.invokeHandlerMethod()-->
ServletInvocableHandlerMethod.invokeAndHandle()
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { //在RequestMappingHandlerAdapter.argumentResolvers的26个解析器中选择1个合适的解析器 // resolver.supportsParameter(parameter)判断哪一个合适 // 然后request.param --> method.param // 例如xxx(User user)时选择ServletModelAttributeMethodProcessor // 最后调用方法执行 Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs); setResponseStatus(webRequest); if (returnValue == null) { if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) { disableContentCachingIfNecessary(webRequest); mavContainer.setRequestHandled(true); return; } } else if (StringUtils.hasText(getResponseStatusReason())) { mavContainer.setRequestHandled(true); return; } mavContainer.setRequestHandled(false); Assert.state(this.returnValueHandlers != null, "No return value handlers"); try { //在RequestMappingHandlerAdapter.returnValueHandlers的15个解析器中选择1个合适的解析器 // handler.supportsReturnType(returnType)判断哪一个合适 // 然后method.result --> response.param, // 例如返回@ResponseBody返回json时选择RequestResponseBodyMethodProcessor // 最后返回 this.returnValueHandlers.handleReturnValue( returnValue, getReturnValueType(returnValue), mavContainer, webRequest); } catch (Exception ex) { if (logger.isTraceEnabled()) { logger.trace(formatErrorForReturnValue(returnValue), ex); } throw ex; } }
1