DispatcherServlet源码剖析
使用Spring MVC时,会在tomcat的上下文配置文件加入类似以下配置:
<web-app>
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.form</url-pattern>
</servlet-mapping>
</web-app>
其实这个配置就是告诉web服务器,符合某正则的url请求都走到spring的DispatcherServlet这个Servlet中,Spring MVC的所有魔法起始就隐藏在这个Servlet中。通过阅读源码一起看一下其中的奥妙。这篇文章看一下DispatcherServlet的初始化过程,通过认识加载过程,了解DispatcherServlet大概是个啥东西。
类模型
从类模型处看,只要搞懂init()方法、doService()方法,基本就OK了。先看一下init()方法。
init()
HttpServletBean.init()方法代码很短,直接贴上来
public final void init() throws ServletException {
// Set bean properties from init parameters.
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
if (!pvs.isEmpty()) {
try {
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
initBeanWrapper(bw);
bw.setPropertyValues(pvs, true);
}
catch (BeansException ex) {
if (logger.isErrorEnabled()) {
logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
}
throw ex;
}
}
// Let subclasses do whatever initialization they like.
initServletBean();
}
关注点主要有:
- addRequiredProperty()方法,继承类可以在构造器中调用此方法,指定Servlet的必须RequiredProperty,可选项共4个ServletName,ServletContext, InitParameter, InitParameterName(ServletConfig接口),指定的property会注入到bean中
- 调用子类initServletBean()方法,子类可定制实现
DispatcherServlet.initStrategies()
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
属性 | 功能 |
---|---|
MultipartResolver | 处理文件上传类请求 |
LocaleResolver | 解析处理请求中的语言设置,渲染时使用 |
ThemeResovler | 解析处理请求中的主题设置,渲染时使用 |
HandlerMapping | 加载context中定义的所有handlerMapping,分别对应不同类型的请求处理,比如静态资源的请求处理、rest接口请求处理等 |
HandlerExceptionResolvers | 处理异常返回渲染 |
ViewResolvers | 根据请求获取到对应的View |
FlashMapManager | FlashMapManager主要用作页面跳转间的通信,参数传递等 |
doDispatch
doDispatch()方法的大致流程如下:
问题
- 通过调试,发现引入了spring-boot-web-starter后,自动加载的handler一共有5个,分别是:
requestMappingHandlerMapping、welcomePageHandlerMapping、beanNameHandlerMapping、routerFunctionMapping,resourceHandlerMapping,这些HandlerMapping是在哪里定义的呢?
答:根据spring-boot的autoconfiure加载原理,从spring.factories找到相关的自动配置类WebMvcAutoConfiguration.class,秘密就在这里面。
相关定义代码块:
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
剩余几个是通过
@Import(EnableWebMvcConfiguration.class)
定义。
EnableWebMvcConfiguration继承DelegatingWebMvcConfiguration继承WebMvcConfigurationSupport,具体代码在WebMvcConfigurationSupport中