[SpringMVC源码剖析] 前奏:梦开始的地方
2017-11-03 15:59
337 查看
SpringMVC源码剖析
纵览:SpringMVC处理请求
本节作为SpringMVC源码剖析的基本,主要介绍以下三方面内容。
1.核心DispatcherServlet的加载方式2.DispatcherServlet初始化过程
3.SpringMVC接收请求并作出响应(粗粒度)
1.核心DispatcherServlet的加载方式
1.1 传统的JavaWeb工程,以web.xml来配置加载Servlet容器的上下文,这显然有些麻烦。1.2 自从Servlet3.0+的出现,Spring-web模块提供了一种免配置文件,在如Tomcat(支持Servlet3.0+)这样的Servlet容器启动时,自动调用了实现的WebApplicationInitializer(全路径org.springframework.web.WebApplicationInitializer)接口的类的onStartup方法,并将容器的ServletContext往下传递。
public interface WebApplicationInitializer { void onStartup(ServletContext servletContext) throws ServletException; }
1.3 从Spring-web模块的API中,找到子类AbstractAnnotationConfigDispatcherServletInitializer,它间接实现了WebApplicationInitializer接口,父类onStartup方法,首先创建RootWebApplicationContext并设置ContextLoaderListner监听器;其次,注册往servletContext注册DispatcherServlet实例。
public abstract class AbstractDispatcherServletInitializer extends AbstractContextLoaderInitializer { @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); registerDispatcherServlet(servletContext); } protected void registerDispatcherServlet(ServletContext servletContext) { //此处往servletContext添加DispatcherServlet实例 //并为DispatcherServlet添加过滤器 }
1.4 由于AbstractAnnotationConfigDispatcherServletInitializer是抽象类,Spring容器不能注入。它重写了父类创建根ApplicationContext与ServletApplicationContext方法,并抽象出两个方法(用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组)。
public abstract class AbstractAnnotationConfigDispatcherServletInitializer extends AbstractDispatcherServletInitializer { @Override protected WebApplicationContext createRootApplicationContext() { ... } @Override protected WebApplicationContext createServletApplicationContext() { ... } //用来创建根ApplicationContext和ServletApplicationContext容器时,需要注入的组件字类节数组 protected abstract Class<?>[] getRootConfigClasses(); protected abstract Class<?>[] getServletConfigClasses(); }
1.5 因此 我们只需要编写SpringMVCInitializer来继承AbstractAnnotationConfigDispatcherServletInitializer类,让它来帮我们完成对DispatcherServlet实例的加载即可。
2.DispatcherServlet初始化过程
2.1 DispatcherServlet有个静态块,用于加载同包下DispatcherServlet.properties策略文件的内容,代码如下static { try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage()); } }
DispatcherServlet.properties 策略文件的内容
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
2.2 DispatcherServlet作为一个HttpServlet类,在加载时,会调用init方法,查找或创建WebApplication容器并刷新操作(如果使用WebApplicationInitilazer加载方式,RootWebApplicationContext是已经存在了)
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware { @Override public final void init() throws ServletException { initServletBean(); }
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware { @Override protected final void initServletBean() throws ServletException { this.webApplicationContext = initWebApplicationContext(); } protected WebApplicationContext initWebApplicationContext() { WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (this.webApplicationContext != null) { // A context instance was injected at construction time -> use it wac = this.webApplicationContext; if (wac instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac; if (!cwac.isActive()) { ... //刷新,调用cwac.refresh()方法 //触发了ContextRefreshListener.onApplicationEvent方法 //调用FrameworkServlet.this.onApplicationEvent方法 //调用子类,即DispatcherServlet.onRefresh方法 configureAndRefreshWebApplicationContext(cwac); } } } ... return wac; } public void onApplicationEvent(ContextRefreshedEvent event) { this.refreshEventReceived = true; onRefresh(event.getApplicationContext()); } protected void onRefresh(ApplicationContext context) { // 调用子类,即DispatcherServlet.onRefresh方法 } private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { FrameworkServlet.this.onApplicationEvent(event); } }
2.3 调用DispatcherServlet.onRefresh方法,
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } protected void initStrategies(ApplicationContext context) { //判断Spring容器是否存在MultipartResolver,LocaleResolver,ThemeResolver,不存在打印日志 initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //默认行为,加载容器的hadlerMappings,handlerAdapters,handlerExceptionResolvers,并排序 //不存在则加载策略文件 initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); //容器中加载名为viewNameTranslator的解析器, //如果找不到,从策略文件加载第一个Translator,即 //org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator initRequestToViewNameTranslator(context); /默认行为,加载容器的viewResolvers,并排序 //不存在则加载策略文件 initViewResolvers(context); //容器中加载名为flashMapManager, //不存在的话,同上处理,找策略文件中第一个 initFlashMapManager(context); }
3.SpringMVC接收请求并作出响应(粗粒度)
3.1 DispatcherServlet作为httpServlet,当接收到请求时,会调用doService方法@Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { //往request设置setAttribute,将当前环境(本地化解析器,主题解析器等)给request,方法mvc框架其他组件可以获取到。 ... try { //真实调用 doDispatch(request, response); } finally { //为request设置WebAsyncManager属性 //如果是同步请求,恢复请求前的属性 ... } }
3.2 DispatcherServlet的doDistpach方法,才是接收请求的核心方法
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 { //判断request头部ContentType是否以"multipart/"开头,来标记是否为附件上传 processedRequest = checkMultipart(request); //是否附件请求标记 multipartRequestParsed = (processedRequest != request); // // 从handlerMappings(RequestMappingHanderMapping,策略文件的handlerMapping类已经过时了),获取HandlerExecutionChain //HandlerExecutionChain(包含一个handlerMethod,以及一堆handlerInterceptor) mappedHandler = getHandler(processedRequest); //找不到handlerMethod时,根据标是否抛出异常,还是直接response.sendError if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // 根据handerMethod找到HandlerAdapter(RequestMappingHandlerAdapter) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 修改 last-modified 头部,如果支持的话. 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; } } // 调用所有HandlerInterceptor的preHandle()方法,如果返回false,不处理请求 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 核心:::::通过RequestMappingHandlerAdapter的handle方法,处理请求逻辑,返回ModelView mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } //从viewNameTranslator中获取默认视图名,并设置到mv中 applyDefaultViewName(request, mv); //调用所有HandlerInterceptor的postHandle()方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } //渲染请求结果 //从ModelView中获取View //view.render(model,req,resp)渲染 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { //调用handerExecutionChain的afterCompletion triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { //调用handerExecutionChain的afterCompletion triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // 调用handerExecutionChain的applyAfterConcurrentHandlingStarted,实现异步拦截 if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // 如果为附件请求,清理现场 if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
注:从DispatcherServlet.properties知道默认的HandlerMapping实现类已经注解了@Deprecated,从注释头部得知,建议使用RequestMappingHandlerMapping类。Spring-Webmvc模块中,提供了@EnableWebMvc,它导入了@Import(DelegatingWebMvcConfiguration.class)DelegatingWebMvcConfiguration类,而DelegatingWebMvcConfiguration类继承了WebMvcConfigurationSupport,WebMvcConfigurationSupport又注入了RequestMappingHandlerMapping实例,如下面代码。所以可以通过注解@EnableWebMvc,向容器注入RequestMappingHandlerMapping实例。
@Bean public RequestMappingHandlerMapping requestMappingHandlerMapping() { RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping(); handlerMapping.setOrder(0); handlerMapping.setInterceptors(getInterceptors()); //注入内容协商管理器handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager()); PathMatchConfigurer configurer = getPathMatchConfigurer(); if (configurer.isUseSuffixPatternMatch() != null) { handlerMapping.setUseSuffixPatternMatch(configurer.isUseSuffixPatternMatch()); } if (configurer.isUseRegisteredSuffixPatternMatch() != null) { handlerMapping.setUseRegisteredSuffixPatternMatch(configurer.isUseRegisteredSuffixPatternMatch()); } if (configurer.isUseTrailingSlashMatch() != null) { handlerMapping.setUseTrailingSlashMatch(configurer.isUseTrailingSlashMatch()); } if (configurer.getPathMatcher() != null) { handlerMapping.setPathMatcher(configurer.getPathMatcher()); } if (configurer.getUrlPathHelper() != null) { handlerMapping.setUrlPathHelper(configurer.getUrlPathHelper()); } return handlerMapping; }
注:RequestMappingHandlerMapping间接实现了InitializingBean接口,重写afterPropertiesSet,代码如下
@Override public void afterPropertiesSet() { if (this.useRegisteredSuffixPatternMatch) { this.fileExtensions.addAll(this.contentNegotiationManager.getAllFileExtensions()); } //调用父类 super.afterPropertiesSet(); }
@Override public void afterPropertiesSet() { initHandlerMethods();//初始化handlerMethods } protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); //收集所有注解了@Controller或@RequestMapping的方法 for (String beanName : beanNames) { if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
下节将细化介绍DispatcherServlet的getHandler(HttpServletRequest request)方法为入口进行源码剖析,将了解到
如何获取到handlerMethod
如何获取handlerInterceptor
如何创建handlerExecutionChain
相关文章推荐
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
- SpringMVC源码剖析(一)- 从抽象和接口说起
- SpringMVC源码剖析(五) - 消息转换器HttpMessageConverter
- SpringMVC源码剖析(五)-消息转换器HttpMessageConverter
- 原 荐 SpringMVC源码剖析(三)- DispatcherServlet的初始化流程
- SpringMVC源码剖析(二)- DispatcherServlet的初始化
- SpringMVC源码剖析(一)- 从抽象和接口说起
- SpringMVC源码剖析(一)- 从抽象和接口说起
- SpringMVC源码剖析(二)SpringMVC是如何处理请求的
- SpringMVC源码剖析(五)-消息转换器
- SpringMVC源码剖析(五)-消息转换器HttpMessageConverter
- SpringMVC源码剖析(一)- 从抽象和接口说起
- SpringMVC源码剖析(五)-消息转换器HttpMessageConverter
- SpringMVC源码剖析(二)- DispatcherServlet的前世今生
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
- SpringMVC源码剖析(一)- 从抽象和接口说起
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
- SpringMVC源码剖析-消息转换器HttpMessageConverter
- SpringMVC源码剖析(四)- DispatcherServlet请求转发的实现
- SpringMVC源码剖析(一)- 从抽象和接口说起