在分析请求的处理流程之前,还是很有必要清楚DispatcherServlet的初始化过程是怎么回事,毕竟这个过程会初始化很多处理请求的组件,不然不知道这些组件是在什么之后以及怎么样被创建的。所以本文以Servlet规范的init方法作为入口,分析一下整个DispatcherServlet的初始化过程。
DispatcherServlet的继承体系
黄线上面的3个接口或类属于是Servlet规范提供的,下面3个类是Spring框架提供的。Servlet容器最开始调用上层的init方法,然后调用链条依次向下。
GenericServlet
在上面整个继承体系中,只有该类实现了Servlet接口的init方法,所以一开始会调用该方法。该类中的实现很简单,就只是赋值保存了一下ServletConfig对象,然后调用该类定义的无参的init方法,这是一个模板方法,由子类重写。在上面的继承体系中,HttpServletBean重写了该方法。
@Override
public void init(ServletConfig config) throws ServletException {
this.config = config;
this.init();
}
// 模板方法,由子类实现
public void init() throws ServletException {
// NOOP by default
}
HttpServletBean
/*
* Servlet容器初始化DispatcherServlet时,首先执行的是该方法
*/
@Override
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.
// 允许子类做额外的初始化操作,但不允许其重写init方法,所以为什么init方法被final修饰。
initServletBean();
}
protected void initServletBean() throws ServletException {
// 模板方法,让子类实现
}
FrameworkServlet
@Override
protected final void initServletBean() throws ServletException {
try {
/*
* 初始化Spring的子容器
*/
this.webApplicationContext = initWebApplicationContext();
/*
* 一样的套路,留给子类实现初始化操作
* 不过DispatcherServlet并没有重写该方法,所以这里是空操作。
*/
initFrameworkServlet();
}
catch (ServletException | RuntimeException ex) {
logger.error("Context initialization failed", ex);
throw ex;
}
}
protected void initFrameworkServlet() throws ServletException {
}
protected WebApplicationContext initWebApplicationContext() {
// 从servlet上下文中获取spring的root容器
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
/*
* 在Servlet容器启动时,如果经过了AbstractDispatcherServletInitializer的处理,那么这里肯定是不会为null的
* this.webApplicationContext是在AbstractDispatcherServletInitializer处创建DispatcherServlet时进行赋值的
*/
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;
// 如果未被激活,在SpringBoot中这里不满足条件
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
// 如果没有设置过父级
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent -> set
// the root application context (if any; may be null) as the parent
// 将root容器设置为父容器
cwac.setParent(rootContext);
}
// 配置和刷新web应用上下文
configureAndRefreshWebApplicationContext(cwac);
}
}
}
// 在SpringBoot的默认自动配置下,这里不满足条件
if (wac == null) { // 如果是常见的基于web.xml的方式,这里满足条件
// No context instance was injected at construction time -> see if one
// has been registered in the servlet context. If one exists, it is assumed
// that the parent context (if any) has already been set and that the
// user has performed any initialization such as setting the context id
wac = findWebApplicationContext();
}
// 在SpringBoot的默认自动配置下,这里不满足条件
if (wac == null) { // 一般这里仍然为null,符合条件
// No context instance is defined for this servlet -> create a local one
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) { // 确保只会执行一次
// Either the context is not a ConfigurableApplicationContext with refresh
// support or the context injected at construction time had already been
// refreshed -> trigger initial onRefresh manually here.
synchronized (this.onRefreshMonitor) {
// 调用子类的重写实现
onRefresh(wac);
}
}
if (this.publishContext) {
// Publish the context as a servlet context attribute.
// 获取web上下文的名称
String attrName = getServletContextAttributeName();
// 把web上下文也放入到servlet的上下文中
getServletContext().setAttribute(attrName, wac);
}
return wac;
}
protected void onRefresh(ApplicationContext context) {
// For subclasses: do nothing by default.
}
这里会涉及到Spring中子容器的初始化,然后调用模板方法initFrameworkServlet,但是默认是空实现,而且DispatcherServlet没有重写该方法,所以这里没有做任何操作。 在initWebApplicationContext中会调用onRefresh这个模板方法,下面来看看DispatcherServlet中是怎么实现的?
DispatcherServlet
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 初始化文件上传解析器
initMultipartResolver(context);
// 初始化本地化解析器
initLocaleResolver(context);
// 初始化主题解析器
initThemeResolver(context);
// 初始化handler映射
initHandlerMappings(context);
// 初始化handler适配器
initHandlerAdapters(context);
// 初始化handler异常解析器
initHandlerExceptionResolvers(context);
// 初始化请求视图名转换器
initRequestToViewNameTranslator(context);
// 初始化视图解析器
initViewResolvers(context);
// 初始化flash映射管理器
initFlashMapManager(context);
}
可以看到,这里初始化了很多组件,本文选择一部分重要的组件来介绍。在介绍具体的组件加载之前,介绍一下 DispatcherServlet的默认策略机制。
默认策略
DispatcherServlet在初始化各种资源时,如果发现bean工厂中没有相关的bean,则可以使用预定义好的默认配置。
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
if (defaultStrategies == null) {
try {
// 加载类路径下属性文件
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
// 从dispatcherServlet.properties文件中加载默认的策略
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
}
// 获取策略类型,即要获取默认配置哪种组件
String key = strategyInterface.getName();
// 获取预配置好的组件名称
String value = defaultStrategies.getProperty(key);
if (value != null) {
// 字符串分割
String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
// 保存实例化好的组件对象
List<T> strategies = new ArrayList<>(classNames.length);
// 遍历类名
for (String className : classNames) {
try {
// 加载类
Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
// 对类进行实例化
Object strategy = createDefaultStrategy(context, clazz);
// 添加到列表中
strategies.add((T) strategy);
}
}
// 返回组件对象列表
return strategies;
}
else {
return Collections.emptyList();
}
}
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.method.annotation.RequestMappingHandlerMapping,\
org.springframework.web.servlet.function.support.RouterFunctionMapping
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
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
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
initMultipartResolver
/** Well-known name for the MultipartResolver object in the bean factory for this namespace. */
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
private void initMultipartResolver(ApplicationContext context) {
try {
/*
* 获取名为multipartResolver的bean
*/
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
}
}
这里在从bean工厂中查找名称为multipartResolver的bean。在Spring Boot中,默认提供了一个叫作MultipartAutoConfiguration的自动配置类,会注册一个名称就是multipartResolver的bean。
/*
* 默认是StandardServletMultipartResolver,而不是CommonsMultipartResolver
*/
@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
@ConditionalOnMissingBean(MultipartResolver.class)
public StandardServletMultipartResolver multipartResolver() {
// 创建StandardServletMultipartResolver对象
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
initHandlerMappings
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 默认为true
if (this.detectAllHandlerMappings) {
// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
// 从bean工厂中获取所有的HandlerMapping类型的bean
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
// 如果获取到了bean
if (!matchingBeans.isEmpty()) {
// 转换成链表
this.handlerMappings = new ArrayList<>(matchingBeans.values());
// We keep HandlerMappings in sorted order.
// 进行排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
/*
* 在Spring Boot的默认自动配置下,上面是会获取到bean的,所以这里是不满足条件的。
*/
if (this.handlerMappings == null) {
// 获取默认策略
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
}
for (HandlerMapping mapping : this.handlerMappings) {
// 是否使用路径模式
if (mapping.usesPathPatterns()) {
this.parseRequestPath = true;
break;
}
}
}
其实这里主要关注RequestMappingHandlerMapping就可以了,这是最常用的一种,而且排序后在列表中的第一个。
initHandlerAdapters
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// 默认是true
if (this.detectAllHandlerAdapters) {
// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
// 从bean工厂中加载所有HandlerAdapter类型的bean
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
// 如果加载到bean
if (!matchingBeans.isEmpty()) {
// 将加载到的bean放入列表中
this.handlerAdapters = new ArrayList<>(matchingBeans.values());
// We keep HandlerAdapters in sorted order.
// 进行排序
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
/*
* 如果上面没有加载到bean,则使用默认策略。
* 但是在Spring Boot的默认自动配置下,这里是不会满足条件的。
*/
if (this.handlerAdapters == null) {
// 获取默认策略
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
}
}
这里关注最常用的RequestMappingHandlerAdapter就行,排序后位于列表第一个。
initHandlerExceptionResolvers
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
if (this.detectAllHandlerExceptionResolvers) { // 默认为true
// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
// 从bean工厂中获取所有类型为HandlerExceptionResolver的bean
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
// 如果获取到bean
if (!matchingBeans.isEmpty()) {
// 将bean放入列表中
this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
// We keep HandlerExceptionResolvers in sorted order.
// 进行排序
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
// 上面没有加载到bean
if (this.handlerExceptionResolvers == null) {
// 获取默认策略
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
}
}
其实这几个方法的逻辑都差不多,Spring完全可以将其公共逻辑抽取出来,不同点可以通过参数来支持。
总结
本文介绍了Spring中DispatcherServlet的初始化过程,比较重要的是初始化了一些组件。这些组件就是用来处理网络请求的,后续会深入各个组件的工作原理。