加入收藏 | 设为首页 | 会员中心 | 我要投稿 甘南站长网 (https://www.0941zz.com/)- 科技、行业物联网、开发、云计算、云管理!
当前位置: 首页 > 运营中心 > Tomcat > 正文

Spring boot整合tomcat底层原理解析

发布时间:2023-02-20 09:59:06 所属栏目:Tomcat 来源:互联网
导读:从源码层面理解spring boot的默认web容器,以及他们是如何关联起来的。 源码基于spring boot2.6.6 项目的pom.xml中存在spring-boot-starter-web的时候,在项目启动时候就会自动启动一个Tomcat。 自动配置类ServletWebServerFactoryAutoConfiguration找到系统

  }
 
  spring boot启动的时候启动tomcat
  SpringBoot的启动过程中,会调用核心的refresh方法,内部会执行onRefresh()方法,onRefresh()方法是一个模板方法,他会执行会执行子类ServletWebServerApplicationContext的onRefresh()方法。
 
  protected void onRefresh() {
      // 模板方法,先调用它父类的,一般是空方法
      super.onRefresh();
      try {
          // 创建web容器
          createWebServer();
      }
      catch (Throwable ex) {
          throw new ApplicationContextException("Unable to start web server", ex);
      }
  }
  这个方法会调用createWebServer()方法。
 
 
  // 最核心的俩行代码
  private void createWebServer() {
      ......
      // 获取web容器,多个或者没有的时候报错
      ServletWebServerFactory factory = getWebServerFactory();
  
      // 调用这个容器的getWebServer方法,上面的启动tomcat的方法!
      this.webServer = factory.getWebServer(getSelfInitializer());
      ......
  }
  getWebServerFactory控制项目组有且只能有一个web容器!

  protected ServletWebServerFactory getWebServerFactory() {
      // Use bean names so that we don't consider the hierarchy
  
      // 得到所有类型为ServletWebServerFactory的Bean。TomcatServletWebServerFactory、JettyServletWebServerFactory、UndertowServletWebServerFactory都是他得到子类!
      String[] beanNames = getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
  
      // 不存在,报错
      if (beanNames.length == 0) {
          throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
      }
  
      // 存在不止一个,报错!
      if (beanNames.length > 1) {
          throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
      }
  
      // 返回唯一的一个web容器!
      return getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
  }
 
  获取tomcat的配置
  自动配置类ServletWebServerFactoryAutoConfiguration上除了import三个web容器,还import了BeanPostProcessorsRegistrar。
  BeanPostProcessorsRegistrar实现了ImportBeanDefinitionRegistrar,所以他会在spring启动的时候调用registerBeanDefinitions方法。
  registerBeanDefinitions会注册一个Bean:webServerFactoryCustomizerBeanPostProcessor。

  public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
      // Bean工厂,一个Aware回调进行赋值
      if (this.beanFactory == null) {
          return;
      }
      // 注册webServerFactoryCustomizerBeanPostProcessor这个Bean。
      registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor",
          WebServerFactoryCustomizerBeanPostProcessor.class,
          WebServerFactoryCustomizerBeanPostProcessor::new);
  
      // 注册errorPageRegistrarBeanPostProcessor
      registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor",
          ErrorPageRegistrarBeanPostProcessor.class, ErrorPageRegistrarBeanPostProcessor::new);
  }
  webServerFactoryCustomizerBeanPostProcessor实现了BeanPostProcessor,所以他会在启动的时候调用postProcessBeforeInitialization方法。

  private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
      // 找到WebServerFactoryCustomizer的Bean
      LambdaSafe.callbacks(WebServerFactoryCustomizer.class, getCustomizers(), webServerFactory)
          // 标记日志用的类
          .withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
          // 调用customize方法,传入webServerFactory
          .invoke((customizer) -> customizer.customize(webServerFactory));
  }
  postProcessBeforeInitialization中会调用WebServerFactoryCustomizer类customize方法,在系统中的唯一实现:ServletWebServerFactoryCustomizer的customize方法。
  customize把配置中的内容设置到ConfigurableServletWebServerFactory对象中。他的实现TomcatServletWebServerFactory在启动的时候就会有值!
 
  @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()::isRegisterDefaultServlet).to(factory::setRegisterDefaultServlet);
      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);
      map.from(this.serverProperties.getShutdown()).to(factory::setShutdown);
      for (WebListenerRegistrar registrar : this.webListenerRegistrars) {
          registrar.register(factory);
      }
      if (!CollectionUtils.isEmpty(this.cookieSameSiteSuppliers)) {
          factory.setCookieSameSiteSuppliers(this.cookieSameSiteSuppliers);
      }
  }
 
  ServletWebServerFactoryCustomizer这个Bean是哪里的?
  在我们自动配置类ServletWebServerFactoryAutoConfiguration中定义。
 
  @Bean
  public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties, ObjectProvider<WebListenerRegistrar> webListenerRegistrars, ObjectProvider<CookieSameSiteSupplier> cookieSameSiteSuppliers) {

(编辑:甘南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读