SpringMVC源码解析<一>

4,169 阅读6分钟

一、SpringBoot自动配置MVC

1.1 ServletWebServerFactoryAutoConfiguration

@Configuration(proxyBeanMethods = false)
//在自动配置中具有最高优先级执行
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
//导致web注册器和服务器
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

1.1.1 EmbeddedTomcat(默认web服务器)

由条件装配的注解 @ConditionalOnClass 可以看到,当前 classpath 下必须有 Tomcat 这个类,该配置类才会生效

spring-boot-starter-web 中默认导入的是 Tomcat 的依赖

@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {

    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }

}

1.1.2 EmbeddedJetty

导入需要有Server和Loader

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class, WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedJetty {

}

使用Jetty需要先排除Tomcat然后导入Jetty的依赖

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-web</artifactId>  
    <exclusions>  
        <exclusion>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-tomcat</artifactId>  
        </exclusion>  
    </exclusions>  
</dependency>  

<!-- Jetty适合长连接应用,就是聊天类的长连接 -->  
<!-- 使用Jetty,需要在spring-boot-starter-web排除spring-boot-starter-tomcat,因为SpringBoot默认使用tomcat -->  
<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-jetty</artifactId>  
</dependency>  

1.1.3 EmbeddedUndertow

Undertow它是一个轻量级Web服务器,但不像传统的 Web 服务器有容器概念,加载一个 Web 应用可以小于 10MB 内存,它提供了对Servlet3.1的支持(支持异步),对Web Socket完全支持,用以满足 Web 应用巨大数量的客户端,它不需要容器,只需通过API即可快速搭建Web服务器

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedUndertow {
}

使用undertow也需要先排除Tomcat然后导入undertow的依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

1.1.4 ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar

这里会注入两个组件ErrorPageRegistrarBeanPostProcessor(处理错误页面)WebServerFactoryCustomizerBeanPostProcessor(用于创建Tomcat容器)

创建详情:juejin.cn/post/720838…

public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

    // ......

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
            BeanDefinitionRegistry registry) {
        if (this.beanFactory == null) {
            return;
        }
        // 编程式注入组件
        registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
                WebServerFactoryCustomizerBeanPostProcessor.class);
        registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
                ErrorPageRegistrarBeanPostProcessor.class);
    }

    private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class<?> beanClass) {
        if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
            RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
            beanDefinition.setSynthetic(true);
            registry.registerBeanDefinition(name, beanDefinition);
        }
    }

}

SpringBoot集成SpringMVC (2).png

1.2 DispatcherServletAutoConfiguration

这里注册了MVC的核心组件DispatcherServlet

// 最高配置优先级
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
// Servlet环境下才生效
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

    public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

    public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

    // 注册DispatcherServlet的配置类
    @Configuration
    @Conditional(DefaultDispatcherServletCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    // 启用配置文件与Properties的映射
    @EnableConfigurationProperties({ HttpProperties.class, WebMvcProperties.class })
    protected static class DispatcherServletConfiguration {

        private final HttpProperties httpProperties;

        private final WebMvcProperties webMvcProperties;

        public DispatcherServletConfiguration(HttpProperties httpProperties, WebMvcProperties webMvcProperties) {
            this.httpProperties = httpProperties;
            this.webMvcProperties = webMvcProperties;
        }

        // 构造DispatcherServlet
        @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServlet dispatcherServlet() {
            DispatcherServlet dispatcherServlet = new DispatcherServlet();
            dispatcherServlet.setDispatchOptionsRequest(this.webMvcProperties.isDispatchOptionsRequest());
            dispatcherServlet.setDispatchTraceRequest(this.webMvcProperties.isDispatchTraceRequest());
            dispatcherServlet
                .setThrowExceptionIfNoHandlerFound(this.webMvcProperties.isThrowExceptionIfNoHandlerFound());
            dispatcherServlet.setEnableLoggingRequestDetails(this.httpProperties.isLogRequestDetails());
            return dispatcherServlet;
        }

        // 注册文件上传组件
        @Bean
        @ConditionalOnBean(MultipartResolver.class)
        @ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
        public MultipartResolver multipartResolver(MultipartResolver resolver) {
            // Detect if the user has created a MultipartResolver but named it incorrectly
            return resolver;
        }
    }

    // 注册DispatcherServletRegistration的配置类
    @Configuration
    @Conditional(DispatcherServletRegistrationCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    @EnableConfigurationProperties(WebMvcProperties.class)
    @Import(DispatcherServletConfiguration.class)
    protected static class DispatcherServletRegistrationConfiguration {

        private final WebMvcProperties webMvcProperties;

        private final MultipartConfigElement multipartConfig;

        public DispatcherServletRegistrationConfiguration(WebMvcProperties webMvcProperties,
                ObjectProvider<MultipartConfigElement> multipartConfigProvider) {
            this.webMvcProperties = webMvcProperties;
            this.multipartConfig = multipartConfigProvider.getIfAvailable();
        }

        // 辅助注册DispatcherServlet的RegistrationBean
        @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
        @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
        public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {
            DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
                    this.webMvcProperties.getServlet().getPath());
            registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
            registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());
            if (this.multipartConfig != null) {
                registration.setMultipartConfig(this.multipartConfig);
            }
            return registration;
        }
    }
//......

SpringBoot集成SpringMVC (3).png

1.3 WebMvcAutoConfiguration

WebMvcConfiguration中会注入两个核心的组件:处理器适配器处理器映射器以及其他一些相关组件 例如:视图解析器视图名称解析器国际化组件

@Configuration(proxyBeanMethods = false)
//当前环境必须是WebMvc(Servlet)环境
@ConditionalOnWebApplication(type = Type.SERVLET)
//当前运行环境的classpath中必须有Servlet类,DispatcherServlet类,WebMvcConfigurer类
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
//如果没有自定义WebMvc的配置类,则使用本自动配置
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
//必须在以下几个组件之后执行
@AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
      ValidationAutoConfiguration.class })
public class WebMvcAutoConfiguration {

    .....
    

    //注入视图名称解析器
    @Bean
    @ConditionalOnBean(View.class)
    @ConditionalOnMissingBean
    public BeanNameViewResolver beanNameViewResolver() {
       BeanNameViewResolver resolver = new BeanNameViewResolver();
       resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10);
       return resolver;
    }

    //注入视图解析器
    @Bean
    @ConditionalOnBean(ViewResolver.class)
    @ConditionalOnMissingBean(name = "viewResolver", value = ContentNegotiatingViewResolver.class)
    public ContentNegotiatingViewResolver viewResolver(BeanFactory beanFactory) {
       ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
       resolver.setContentNegotiationManager(beanFactory.getBean(ContentNegotiationManager.class));
       // ContentNegotiatingViewResolver uses all the other view resolvers to locate
       // a view so it should have a high precedence
       resolver.setOrder(Ordered.HIGHEST_PRECEDENCE);
       return resolver;
    }

    //注入国际化
    @Bean
    @ConditionalOnMissingBean
    @ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
    public LocaleResolver localeResolver() {
       if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
          return new FixedLocaleResolver(this.mvcProperties.getLocale());
       }
       AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
       localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
       return localeResolver;
    }
    
    //注入处理器适配器
    @Bean
    @Override
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
                    @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
                    @Qualifier("mvcConversionService") FormattingConversionService conversionService,
                    @Qualifier("mvcValidator") Validator validator) {
            RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter(contentNegotiationManager,
                            conversionService, validator);
            adapter.setIgnoreDefaultModelOnRedirect(
                            this.mvcProperties == null || this.mvcProperties.isIgnoreDefaultModelOnRedirect());
            return adapter;
    }


    //注入处理器映射器
    @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);
    }


}

SpringBoot集成SpringMVC.png

二、RequestMappingHandlerMapping:注册Controller

public void afterPropertiesSet() {
   //创建Mapping配置
   this.config = new RequestMappingInfo.BuilderConfiguration();
   //解析请求中的路径
   this.config.setUrlPathHelper(getUrlPathHelper());
   //路径匹配校验器
   this.config.setPathMatcher(getPathMatcher());
   //是否支持后缀补充,默认为true
   this.config.setSuffixPatternMatch(useSuffixPatternMatch());
   //是否添加"/"后缀,默认为true
   this.config.setTrailingSlashMatch(useTrailingSlashMatch());
   //是否采用mediaType匹配模式,比如.json/.xml模式的匹配,默认为false  
   this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
   //mediaType处理类
   this.config.setContentNegotiationManager(getContentNegotiationManager());
   //调用父类进行HandlerMethod的注册工作
   super.afterPropertiesSet();
}

父类AbstractHandlerMethodMapping#afterPropertiesSet

@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

处理没有被代理的Bean(Bean名称不是scopedTarget.开头)

@Scope标注的对象,如果代理模式是jdk或者cglib代理的话,会在spring容器中产生2个bean,一个是代理的bean,一个是原始的bean,原始的bean的beanName被ScopedProxyUtils命名为:scopedTarget.xx:

private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";

protected void initHandlerMethods() {
   for (String beanName : getCandidateBeanNames()) {
      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
         //处理候选Bean
         processCandidateBean(beanName);
      }
   }
   //打印mapper注册的数量日志
   handlerMethodsInitialized(getHandlerMethods());
}

获取被@Controller@RequestMapping注解标注的Bean

protected void processCandidateBean(String beanName) {
   Class<?> beanType = null;
   try {
      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);
      }
   }
   //判断是否有@Controller 或 @RequestMapping 注解
   if (beanType != null && isHandler(beanType)) {
      detectHandlerMethods(beanName);
   }
}

解析方法

protected void detectHandlerMethods(Object handler) {
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
      Class<?> userType = ClassUtils.getUserClass(handlerType);
      //2.1 解析筛选方法
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                  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));
      }
      //2.2 注册方法映射
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}

2.1 MethodIntrospector.selectMethods:解析筛选方法

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
   final Map<Method, T> methodMap = new LinkedHashMap<>();
   Set<Class<?>> handlerTypes = new LinkedHashSet<>();
   Class<?> specificHandlerType = null;
   //不是代理类
   if (!Proxy.isProxyClass(targetType)) {
      specificHandlerType = ClassUtils.getUserClass(targetType);
      handlerTypes.add(specificHandlerType);
   }
   //获取所有接口类
   handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

   for (Class<?> currentHandlerType : handlerTypes) {
      final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

      ReflectionUtils.doWithMethods(currentHandlerType, method -> {
         //获取具体的方法
         Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
         //筛选方法--》会进入回调函数
         T result = metadataLookup.inspect(specificMethod);
         if (result != null) {
            Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
            if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
               //将方法作为key 封装的RequestMappingInfo作为value放入map中
               methodMap.put(specificMethod, result);
            }
         }
      }, ReflectionUtils.USER_DECLARED_METHODS);
   }

   return methodMap;
}

这里会进入外层的方法

{
   try {
      return getMappingForMethod(method, userType);
   }
   catch (Throwable ex) {
      throw new IllegalStateException("Invalid mapping on handler class [" +
            userType.getName() + "]: " + method, ex);
   }
}
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    // 1.1.1 创建方法级别的RequestMappingInfo  /testMethod
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
        // 1.1.1 创建类级别的RequestMappingInfo  /test
        RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
        //拼接方法上的 @RequestMapping路径  /test/testMethod
        if (typeInfo != null) {
            info = typeInfo.combine(info);
        }
        // 1.1.2 拼接路径前缀
        String prefix = getPathPrefix(handlerType);
        if (prefix != null) {
            info = RequestMappingInfo.paths(prefix).build().combine(info);
        }
    }
    return info;
}

2.1.1 createRequestMappingInfo:创建MappingInfo

private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
   //获取方法上的@RequestMapping注解
   RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
   //获取方法判断器
   RequestCondition<?> condition = (element instanceof Class ?
         getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
   //如果有@RequestMapping注解包装成RequestMappingInfo
   return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

将@RequestMapping注解信息包装成RequestMappingInfo

protected RequestMappingInfo createRequestMappingInfo(
      RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

   RequestMappingInfo.Builder builder = RequestMappingInfo
         .paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
         .methods(requestMapping.method())
         .params(requestMapping.params())
         .headers(requestMapping.headers())
         .consumes(requestMapping.consumes())
         .produces(requestMapping.produces())
         .mappingName(requestMapping.name());
   if (customCondition != null) {
      builder.customCondition(customCondition);
   }
   return builder.options(this.config).build();
}

2.1.2 getPathPrefix:拼接路径前缀

private Map<String, Predicate<Class<?>>> pathPrefixes = new LinkedHashMap<>();

String getPathPrefix(Class<?> handlerType) {
   
   //获取路径前缀
   for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
      if (entry.getValue().test(handlerType)) {
         String prefix = entry.getKey();
         if (this.embeddedValueResolver != null) {
            prefix = this.embeddedValueResolver.resolveStringValue(prefix);
         }
         return prefix;
      }
   }
   return null;
}

WebMvcAutoConfiguration在初始化的时候设置了pathPrefixes

2.2 注册方法映射

methods.forEach((method, mapping) -> {
    Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
    registerHandlerMethod(handler, invocableMethod, mapping);
});

注册Mapping

protected void registerHandlerMethod(Object handler, Method method, RequestMappingInfo mapping) {
   //注册Mapping
   super.registerHandlerMethod(handler, method, mapping);
   updateConsumesCondition(mapping, method);
}
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
   this.mappingRegistry.register(mapping, handler, method);
}

这里会将Mapping注册进urlLookupmappingLookupregistry

private final Map<T, MappingRegistration<T>> registry = new HashMap<>();
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();


public void register(T mapping, Object handler, Method method) {
    // 读写锁加锁
    this.readWriteLock.writeLock().lock();
    try {
        // 将Controller的类型和Controller中的方法包装为一个HandlerMethod对象
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        assertUniqueMethodMapping(handlerMethod, mapping);
        // 将RequestMappingInfo和Controller的目标方法存入Map中
        this.mappingLookup.put(mapping, handlerMethod);

        // 将注解中的映射url和RequestMappingInfo存入Map
        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        if (getNamingStrategy() != null) {
            name = getNamingStrategy().getName(handlerMethod, mapping);
            addMappingName(name, handlerMethod);
        }

        // 将Controller目标方法和跨域配置存入Map
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }

        // uri 映射 HandlerMethod封装的MappingRegistration对象,存入Map中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}

image.png

三、DispatcherServlet#onRefresh:初始化web容器(第一次请求)

第一次请求进来是会进行Servlet初始化,Servlet的init()方法会被调用。 进入 DispatcherServlet中,发现并没有该方法,那么肯定在它集成的父类上。
DispatcherServlet 继承于 FrameworkServlet,结果还是没找到,继续找它的父类 HttpServletBean

@Override
public final void init() throws ServletException {
    //获取配置web.xml中的参数
    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;
        }
    }
    //重点:一个空方法,模板模式,子类FrameworkServlet,重写了它
    initServletBean();
}

FrameworkServlet

@Override
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
    if (logger.isInfoEnabled()) {
        logger.info("Initializing Servlet '" + getServletName() + "'");
    }
    long startTime = System.currentTimeMillis();

    try {
        //重点:初始化WebApplicationContext
        this.webApplicationContext = initWebApplicationContext();
        //一个空方法,可以提供给以后的子类复写,做一些初始化的事情,暂时没有被复写
        initFrameworkServlet();
    }
    catch (ServletException | RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        throw ex;
    }

    //省略无关代码...
}

initWebApplicationContext()方法是初始化 WebApplicationContext的,而它集成于 ApplicationContext,所以它也是一个IoC容器。

所以 FrameworkServlet类的职责是将 SpringServler 进行一个关联。

这个方法,除了初始化WebApplicationContext外,还调用了一个 onRefresh()方法,又是模板模式,空方法,让子类复写进行逻辑处理,例如子类DispatcherServlet重写了它

protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
            WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    //有参数构造方法,传入webApplicationContext对象,就会进入该判断
    if (this.webApplicationContext != null) {
        wac = this.webApplicationContext;
        if (wac instanceof ConfigurableWebApplicationContext) {
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
            //还没初始化过,容器的refresh()还没有调用
            if (!cwac.isActive()) {
                //设置父容器
                if (cwac.getParent() == null) {
                    cwac.setParent(rootContext);
                }
                configureAndRefreshWebApplicationContext(cwac);
            }
        }
    }
    if (wac == null) {
        //获取ServletContext,之前通过setAttribute设置到了ServletContext中,现在通过getAttribute获取到
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        //创建WebApplicationContext,设置环境environment、父容器,本地资源文件
        wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
        synchronized (this.onRefreshMonitor) {
            //刷新,也是模板模式,空方法,让子类重写进行逻辑处理,而子类DispatcherServlet重写了它
            onRefresh(wac);
        }
    }

    //用setAttribute(),将容器设置到ServletContext中
    if (this.publishContext) {
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
    }
    return wac;
}

//WebApplicationContext
public interface WebApplicationContext extends ApplicationContext {
    //...
}

DispatcherServlet执行刷新web容器

@Override
protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
}

初始化SpringMVC九大组件

protected void initStrategies(ApplicationContext context) {
    //3.1 初始化multipart类型文件解析器
    initMultipartResolver(context);
    //3.2 初始化用户区域解析器(多语言、国际化)
    initLocaleResolver(context);
    //3.3 初始化主题解析器
    initThemeResolver(context);
    //3.4 初始化映射器(处理Controller的方法和url映射关系)
    initHandlerMappings(context);
    //3.5 初始化适配器,多样写法Controller的适配处理,实现最后返回都是ModelAndView
    initHandlerAdapters(context);
    //3.6 初始化异常处理器
    initHandlerExceptionResolvers(context);
    //3.7 初始化视图转发
    initRequestToViewNameTranslator(context);
    //3.8 初始化视图解析器,将ModelAndView保存的视图信息,转换为一个视图,输出数据
    initViewResolvers(context);
    //3.9 初始化映射处理器
    initFlashMapManager(context);
}

3.1 初始化multipart类型文件解析器

MultipartResolver 用于处理文件上传,当收到请求时 DispatcherServlet 的 checkMultipart() 方法会调用 MultipartResolver 的 isMultipart()方法判断请求中是否包含文件。如果请求数据中包含文件,则调用 MultipartResolver 的 resolveMultipart() 方法对请求的数据进行解析,然后将文件数据解析成 MultipartFile 并封装在 MultipartHttpServletRequest (继承了 HttpServletRequest) 对象中,最后传递给 Controller

初始化时会直接从容器中获取MultipartResolver类型的Bean

public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";

private void initMultipartResolver(ApplicationContext context) {
   try {
      this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
   
}

3.2 初始化用户区域解析器(多语言、国际化)

LocaleResolver其主要作用在于根据不同的用户区域展示不同的视图,而用户的区域也称为Locale,该信息是可以由前端直接获取的。通过这种方式,可以实现一种国际化的目的,比如针对美国用户可以提供一个视图,而针对中国用户则可以提供另一个视图。

初始化时会直接从容器中获取LocaleResolver类型的Bean

public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";

private void initLocaleResolver(ApplicationContext context) {
   try {
      this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
}

3.3 初始化主题解析器

设置整个系统的主题。主题就是系统的整体样式或风格,可通过Spring MVC框架提供的主题(theme)设置应用的整体样式风格,提高用户体验。Spring MVC的主题就是一些静态资源的集合,即包括样式及图片,用来控制应用的视觉风格。

private void initThemeResolver(ApplicationContext context) {
   try {
      this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
}

3.4 初始化映射器

适配器异常处理器视图转发视图解析器映射处理器初始化流程都类似,都是从容器中获取然后进行排序。

//处理器映射集合
@Nullable
private List<HandlerMapping> handlerMappings;
//一个开关,标识是否获取所有的处理器映射,如果为false,则搜寻指定名为的 handlerMapping 的 Bean实例
private boolean detectAllHandlerMappings = true;
//指定的Bean的名称
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";

private void initHandlerMappings(ApplicationContext context) {
    //清空集合
    this.handlerMappings = null;
    
    //一个开关,默认为true,设置为false,才走else的逻辑
    if (this.detectAllHandlerMappings) {
        //重点:在容器中找到所有HandlerMapping
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        //找到了,进行排序,保证顺序
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        //指定搜寻指定名为 handlerMapping 的 HandlerMapping 实例
        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) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }

    //配置文件名
    private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

    //从配置文件中获取配置的组件,其他组件找不到时,也是调用这个方法进行默认配置
    protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
        //...
    }
}