SpringBoot之嵌入式Servlet容器

13 篇文章 1 订阅
6 篇文章 0 订阅

本文主要介绍了SpringBoot下,三大内置Servlet的加载原理以Servlet的启动原理,涉及到部分源码解读。


1、嵌入式Servlet容器加载原理

1.1、ServletWebServerFactoryAutoConfiguration自动配置类。

  ServletWebServerFactoryAutoConfiguration是SpringBoot嵌入式Servlet容器的自动配置类。

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
/**
 * 当javax.servlet.ServletRequest类存在的时候,ServletWebServerFactoryAutoConfiguration才会生效。当我们不引入任何Servlet容器的时候,那么这个
 * javax.servlet.ServletRequest类就会找不到。在pom.xml中增加以下内容就可以证明这点:
 * <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>
 */
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
// 将yml文件中所有的以server开头的配置加载到ServerProperties类中。比如:server.port=8081
@EnableConfigurationProperties(ServerProperties.class)
/**
 * BeanPostProcessorsRegistrar类实现了ImportBeanDefinitionRegistrar接口,这个接口中的方法会在SpringBoot启动的时候调用。
 * 默认导入EmbeddedTomcat、EmbeddedJetty、EmbeddedUndertow三种servlet容器。
 */
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {

   @Bean
   public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
      return new ServletWebServerFactoryCustomizer(serverProperties);
   }

   @Bean
   @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
   public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
         ServerProperties serverProperties) {
      return new TomcatServletWebServerFactoryCustomizer(serverProperties);
   }
}

1.2、ServletWebServerFactoryCustomizer Bean

  ServletWebServerFactoryCustomizer Bean:通用的Servlet容器定制器,实现了WebServerFactoryCustomizer接口,重写了customize()方法,里面设置了Servlet容器的通用的配置。

public class ServletWebServerFactoryCustomizer
      implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

   private final ServerProperties serverProperties;

   public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
      this.serverProperties = serverProperties;
   }

   @Override
   public int getOrder() {
      return 0;
   }

    // 设置了Servlet容器的通用的配置
   @Override
   public void customize(ConfigurableServletWebServerFactory factory) {
      PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
      map.from(this.serverProperties::getPort).to(factory::setPort);
      map.from(this.serverProperties::getAddress).to(factory::setAddress);
      map.from(this.serverProperties.getServlet()::getContextPath).to(factory::setContextPath);
      map.from(this.serverProperties.getServlet()::getApplicationDisplayName).to(factory::setDisplayName);
      map.from(this.serverProperties.getServlet()::getSession).to(factory::setSession);
      map.from(this.serverProperties::getSsl).to(factory::setSsl);
      map.from(this.serverProperties.getServlet()::getJsp).to(factory::setJsp);
      map.from(this.serverProperties::getCompression).to(factory::setCompression);
      map.from(this.serverProperties::getHttp2).to(factory::setHttp2);
      map.from(this.serverProperties::getServerHeader).to(factory::setServerHeader);
      map.from(this.serverProperties.getServlet()::getContextParameters).to(factory::setInitParameters);
   }

}

1.3、TomcatServletWebServerFactoryCustomizer Bean

  TomcatServletWebServerFactoryCustomizer Bean:Tomcat容器的定制器,实现了WebServerFactoryCustomizer接口,重写了customize()方法,里面设置了Tomcat容器的特有的配置。

public class TomcatServletWebServerFactoryCustomizer
      implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {

   private final ServerProperties serverProperties;

   public TomcatServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
      this.serverProperties = serverProperties;
   }

    // 设置了Tomcat容器的特殊的配置
   @Override
   public void customize(TomcatServletWebServerFactory factory) {
       // 获取配置中所有的server.tomcat开头的配置
      ServerProperties.Tomcat tomcatProperties = this.serverProperties.getTomcat();
      if (!ObjectUtils.isEmpty(tomcatProperties.getAdditionalTldSkipPatterns())) {
         factory.getTldSkipPatterns().addAll(tomcatProperties.getAdditionalTldSkipPatterns());
      }
      if (tomcatProperties.getRedirectContextRoot() != null) {
         customizeRedirectContextRoot(factory, tomcatProperties.getRedirectContextRoot());
      }
      if (tomcatProperties.getUseRelativeRedirects() != null) {
         customizeUseRelativeRedirects(factory, tomcatProperties.getUseRelativeRedirects());
      }
   }
    ………省略其他代码……
}

1.4、BeanPostProcessorsRegistrar.class

  ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class:实现了ImportBeanDefinitionRegistrar接口,调用registerBeanDefinitions方法以便提前注册 WebServerFactoryCustomizerPostProcessors,在SpringBoot启动的时候,经过一系列的调用,最终会通过这个WebServerFactoryCustomizerPostProcessors后置处理器找到TomcatServletWebServerFactoryCustomizer定制器去执行customize方法,定制Tomcat容器。

public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware {

   private ConfigurableListableBeanFactory beanFactory;

   @Override
   public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
      if (beanFactory instanceof ConfigurableListableBeanFactory) {
         this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
      }
   }

    // 注册WebServerFactoryCustomizerPostProcessors后置处理器
   @Override
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
         BeanDefinitionRegistry registry) {
      if (this.beanFactory == null) {
         return;
      }
      registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
            WebServerFactoryCustomizerBeanPostProcessor.class);
      registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
            ErrorPageRegistrarBeanPostProcessor.class);
   }

    // 具体注册WebServerFactoryCustomizerPostProcessors后置处理器的逻辑。
   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);
      }
   }

}

1.5、WebServerFactoryCustomizerBeanPostProcessor.class

  WebServerFactoryCustomizerBeanPostProcessor.class:实现了BeanPostProcessor接口,由SpringBoot内部调用。

public class WebServerFactoryCustomizerBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

   private ListableBeanFactory beanFactory;

   private List<WebServerFactoryCustomizer<?>> customizers;

   @Override
   public void setBeanFactory(BeanFactory beanFactory) {
      Assert.isInstanceOf(ListableBeanFactory.class, beanFactory,
            "WebServerCustomizerBeanPostProcessor can only be used " + "with a ListableBeanFactory");
      this.beanFactory = (ListableBeanFactory) beanFactory;
   }

    /**
     * 初始化WebServerFactoryCustomizerBeanPostProcessor之前做的一些事情
     */
   @Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      if (bean instanceof WebServerFactory) {
         postProcessBeforeInitialization((WebServerFactory) bean);
      }
      return bean;
   }

    /**
     * 初始化WebServerFactoryCustomizerBeanPostProcessor之后做的一些事情
     */
   @Override
   public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      return bean;
   }

   /**
    * LambdaSafe.callbacks().withLogger().invoke():支持泛型回调回调的一种写法。
    * - getCustomizers:获取所有的实现了WebServerFactoryCustomizer的实现类集合。
    * - withLogger:这个就是记录日志的一个方法。
    * - invoke:实际上是循环调用getCustomizers返回来的实现类的customize方法。
    */
   @SuppressWarnings("unchecked")
   private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
      LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
            .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
            .invoke((customizer) -> customizer.customize(webServerFactory));
   }

   // 返回WebServerFactoryCustomizer的实现类集合。
   private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
      if (this.customizers == null) {
         // Look up does not include the parent context
         this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
         this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
         this.customizers = Collections.unmodifiableList(this.customizers);
      }
      return this.customizers;
   }

    // 从beanFactory中获取WebServerFactoryCustomizer的实现类集合。
   @SuppressWarnings({ "unchecked", "rawtypes" })
   private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
      return (Collection) this.beanFactory.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
   }
}

2、嵌入式Servlet容器启动原理(以EmbeddedTomcat为例)

  ServletWebServerFactoryAutoConfiguration在加载的时候,导入了三个内置Servlet容器,例如:EmbeddedTomcat

@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
      ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
      ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
      ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })

2.1、EmbeddedTomcat.class

  Tomcat容器的配置类,该类在常规自动配置类中@Import,以保证它的执行。

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

    // 创建Tomcat容器服务工厂TomcatServletWebServerFactory Bean
   @Bean
   public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
      return new TomcatServletWebServerFactory();
   }
}

2.2、TomcatServletWebServerFactory Bean

  TomcatServletWebServerFactory是用来创建TomcatWebServer的抽象web服务的抽象工厂类。此工厂类默认创建监听端口8080的HTTP请求的容器。

public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
      implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
    @Override
	public WebServer getWebServer(ServletContextInitializer... initializers) {
		/**
		   这里先new了一个Tomcat对象,默认端口8080,请求地址localhost
            public class Tomcat {
                protected int port = 8080;
                protected String hostname = "localhost";
                ……………省略其他代码……………
           }
		 */
        Tomcat tomcat = new Tomcat();
		File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
		tomcat.setBaseDir(baseDir.getAbsolutePath());
		Connector connector = new Connector(this.protocol);
		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);
        // 根据tomcat对象调用getTomcatWebServer获取TomcatWebServe的具体实例。
		return getTomcatWebServer(tomcat);
	}
    
    // 实际上new了一个TomcatWebServer对象
    protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
		return new TomcatWebServer(tomcat, getPort() >= 0);
	}
}

2.3、TomcatWebServer

  用于创建Tomcat web服务器的WebServer。通常,这个类应该由TomcatServletWebServerFactory来调用创建,而不是直接创建。

public class TomcatWebServer implements WebServer {
    // new TomcatWebServer对象的时候,调用initialize()来启动Tomcat
    public TomcatWebServer(Tomcat tomcat, boolean autoStart) {
        Assert.notNull(tomcat, "Tomcat Server must not be null");
        this.tomcat = tomcat;
        this.autoStart = autoStart;
        initialize();
    }

    private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
        synchronized (this.monitor) {
            …………省略其他代码…………
            try {
                // 启动Tomcat服务
                 // Start the server to trigger initialization listeners
                this.tomcat.start();
                // Unlike Jetty, all Tomcat threads are daemon threads. We create a
                // blocking non-daemon to stop immediate shutdown
                startDaemonAwaitThread();
            }
            catch (Exception ex) {
                stopSilently();
                destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", ex);
            }
        }
}

3、使用外部Servlet容器,以Tomcat为例。

  • 更改打包方式为war war
  • 将SpringBoot内置的Tomcat容器的依赖排除掉,让它不参与打包,因为外置的Tomcat容器中已经有相关的jar。
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <scope>provided</scope>
</dependency>
  • 选择在IDEA总选择用Tomcat启动。

3.1、Servlt三大组件及注册方式

3.1.1、Servlt三大组件:Servlet、Filter、Listener

3.1.2、以Servelt为例,讲解在SpringBoot中注册Servelt的方式

  基于Servlet3.0的规范注册Servlet,如果是以SpringBoot的启动类启动,那么必须在启动类上加@ServletComponentScan才能扫描到consumerServlet

// Servlet3.0规范注册Servlet 
@WebServlet(name = "consumerServlet", urlPatterns = "/consumerServlet") 
// Servlet3.0规范注册Listener @WebListener 
// Servlet3.0规范注册Filter @WebFilter 
public class ConsumerServlet extends HttpServlet { 
	@Override 
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { 
	resp.getWriter().write("@WebServlet"); 
	}
}

  基于SpringBoot注解注册Servlet

public class ConsumerSpringBootServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        resp.getWriter().write("ConsumerSpringBootServlet");
    }
}

@Configuration
public class ConsumerConfiguration implements WebMvcConfigurer {
    @Bean
    public ServletRegistrationBean registrationBean() {
        ServletRegistrationBean registrationBean = new ServletRegistrationBean();
        registrationBean.setServlet(new ConsumerSpringBootServlet());
        registrationBean.addUrlMappings("/consumerSpringBootServlet");
        registrationBean.setName("consumerSpringBootServlet");
        return registrationBean;
    }
}

// 如果以SPringBoot启动类启动的项目,那么这个类可以不用。如果是以外部tomcat的方式启动,那么必须要有这个类,才能在外部tomcat启动的方式下,启动SpringBoot。
public class TomcatSupportSpringBoot extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
        return builder.sources(PractiseApplication.class);
    }
}

运行结果:
在这里插入图片描述在这里插入图片描述

总结

本文主要介绍了SpringBoot下,三大内置Servlet的加载原理以Servlet的启动原理,涉及到部分源码解读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜间沐水人

文章编写不易,一分钱也是爱。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值