1、DisptachServlet的注册原理

(1)自动配置DisptcherServletAutoConfiguration

  1. @AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
  2. @Configuration(proxyBeanMethods = false)
  3. @ConditionalOnWebApplication(type = Type.SERVLET)
  4. @ConditionalOnClass(DispatcherServlet.class)
  5. @AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
  6. public class DispatcherServletAutoConfiguration {

(2)容器中注册了一个组件DsipatcherServlet

  1. @Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  2. public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
  3. DispatcherServlet dispatcherServlet = new DispatcherServlet();
  4. dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
  5. dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
  6. dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
  7. dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
  8. dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
  9. return dispatcherServlet;
  10. }

(3)容器中又使用DispatcherServletRegistrationBean向容器中注册了DispatcherServlet

  1. @Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
  2. @ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
  3. public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
  4. WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
  5. DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
  6. webMvcProperties.getServlet().getPath());
  7. registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
  8. registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
  9. multipartConfig.ifAvailable(registration::setMultipartConfig);
  10. return registration;
  11. }
  • 1、发现匹配的路径webMvcProperties.getServlet().getPath()=”/“

    public static class Servlet {
    
          /**
           * Path of the dispatcher servlet. Setting a custom value for this property is not
           * compatible with the PathPatternParser matching strategy.
           */
          private String path = "/";
    
  • Tomcat-Servlet在匹配路径的时候 如果有多个Servlet可以匹配路径的时候,使用精确匹配优先。

    2、原理

    • SpringBoot应用启动发现当前是Web应用,web场景有有tomcat包
    • web应用创建一个web版的ioc容器ServletWebServerApplicationContext
    • ServletWebServerApplicationContext启动的时候寻找ServletWebServerFactory(Servlet的web服务器工厂->Servlet的web服务器)
    • SpringBoot底层默认有很多的WebServlet服务器工厂TomcatServletWebServerFactory, JettyServletWebServerFactory,or UndertowServletWebServerFactory
    • 底层直接会有一个配置类ServletWebServerFactoryAutoConfiguration
    • ServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration(配置类)
    • ServletWebServerFactoryConfiguration配置类,genuine动态判断系统中到底导入了哪个Web服务器的包(默认是web-starter导入的是Tomcat服务器),容器中就有TomcatServletWebServerFactory
    • TomcatServletWebServerFactory中创建出Tomcat服务器
    • 内嵌服务器,就是手动把启动武器的代码调用(tomcat核心jar要包含进来)
      @Override
      public WebServer getWebServer(ServletContextInitializer... initializers) {
         if (this.disableMBeanRegistry) {
             Registry.disableRegistry();
         }
         Tomcat tomcat = new Tomcat();
         File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
         tomcat.setBaseDir(baseDir.getAbsolutePath());
         Connector connector = new Connector(this.protocol);
         connector.setThrowOnFailure(true);
         tomcat.getService().addConnector(connector);
         customizeConnector(connector);
         tomcat.setConnector(connector);
         tomcat.getHost().setAutoDeploy(false);
         configureEngine(tomcat.getEngine());
         for (Connector additionalConnector : this.additionalTomcatConnectors) {
             tomcat.getService().addConnector(additionalConnector);
         }
         prepareContext(tomcat.getHost(), initializers);
         return getTomcatWebServer(tomcat);
      }
      

      3、切换内置服务器

      (1)查到响应的服务器启动环境
      https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
      spring-boot-starter-undertow
      (2)修改pom.xml配置文件,先排除tomcat,再导入对于的服务器
         <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>
      

      3、定制Servlet容器

  • 实现 WebServerFactoryCustomizer

  • 修改配置文件server.xxx(推荐)
  • 自定义ConfigurationServletFactory