一、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容器)

创立详情:/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);
        }
    }
}

SpringMVC源码解析

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;
        }
    }
//......

SpringMVC源码解析

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);
    }
}

SpringMVC源码解析

二、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();
    }
}

SpringMVC源码解析

三、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) {
        //...
    }
}