spring-boot如何得到一个tomcat实例(基于spring-boot_v2.0.6.RELEASE)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/song_java/article/details/86539380

        在上一篇博文spring-boot如何得到一个tomcat实例(基于spring-boot_v1.5.14.RELEASE)中我们介绍了基于spring-boot 1.5.14版本中tomcat的实例化过程,由于2.0版本之后这个实例化过程发生了很大的改变,所以本文将以2.0.6版本为基础介绍tomcat的实例化过程。(https://docs.spring.io/spring-boot/docs/2.0.6.RELEASE/reference/htmlsingle/)

   spring-boot加载tomcat的过程如下:

       (1) springboot的主函数有一个注解 @SpringBootApplication,而这个注解里有一个@EnableAutoConfiguration

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration     //开启自动配置
@ComponentScan(excludeFilters = {
	@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
	@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

      (2) 相比于1.x版本,2.x版本废弃了自动配置类EmbeddedServletContainerAutoConfiguration,而使用了ServletWebServerFactoryAutoConfiguration和EmbeddedWebServerFactoryCustomizerAutoConfiguration两个自动配置类,下面我们分别来介绍一下这两个autoConfiguration

      (3) 我们先看一下比较简单的TomcatWebServerFactoryCustomizer吧

@Configuration
@ConditionalOnWebApplication
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {

   
	@Configuration
     //默认使用tomcat,因此条件满足
	@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class }) 
	public static class TomcatWebServerFactoryCustomizerConfiguration {
        
        // 实例化一个TomcatWebServerFactoryCustomizer实例bean,
        //这个bean实现了WebServerFactoryCustomizer接口,
        //它的customize方法负责对ConfigurableTomcatWebServerFactory进行配置
		@Bean
		public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
		}

	}

    // 由于 Server.class, Loader.class, WebAppContext.class 
    //默认情况下不存在,因此JettyWebServerFactoryCustomizerConfiguration不会生效
	@Configuration
	@ConditionalOnClass({ Server.class, Loader.class, WebAppContext.class })
	public static class JettyWebServerFactoryCustomizerConfiguration {

		@Bean
		public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new JettyWebServerFactoryCustomizer(environment, serverProperties);
		}

	}

    // 由于Undertow.class, SslClientAuthMode.class默认情况下不存在,
    // 因此UndertowWebServerFactoryCustomizerConfiguration不会生效
	@Configuration
	@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
	public static class UndertowWebServerFactoryCustomizerConfiguration {

		@Bean
		public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
				Environment environment, ServerProperties serverProperties) {
			return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
		}
	}
}

     

    (4)然后看一下 ServletWebServerFactoryAutoConfiguration

@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
		ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
		ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
		ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
    
    // 实例化一个 ServletWebServerFactoryCustomizer,它的泛型参数是ConfigurableServletWebServerFactory
	@Bean
	public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new ServletWebServerFactoryCustomizer(serverProperties);
	}

   // 实例化一个TomcatServletWebServerFactoryCustomizer,它的泛型参数是TomcatServletWebServerFactory
	@Bean
	@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
	public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
			ServerProperties serverProperties) {
		return new TomcatServletWebServerFactoryCustomizer(serverProperties);
	}


    // 通过上面的@import引入
	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;
			}
		}

		@Override
		public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
				BeanDefinitionRegistry registry) {
			if (this.beanFactory == null) {
				return;
			}
            //这边的处理跟v1.x版本是一致的, 
            //从beanFactory中获取一个WebServerFactoryCustomizerBeanPostProcessor实例bean,
            //如果不存在,则主动new一个
			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);
			}
		}

	}

}

         ServletWebServerFactoryCustomizer主要做了四件事:

  •  注1:通过@import引入ServletWebServerFactoryConfiguration的几个子类:EmbeddedTomcat、EmbeddedJetty和EmbeddedUndertow,而事实上最终只有EmbeddedTomcat起作用了,如下图,EmbeddedJetty和EmbeddedUndertow缺少依赖的java类,因此不会生效,而唯一生效的EmbeddedTomcat只做了一件事:实例化了一个TomcatServletWebServerFactory的bean,这个bean在 注4 会用到

  • 注2:实例化一个 ServletWebServerFactoryCustomizer的bean(它实现了WebServerFactoryCustomizer接口),它对ConfigurableServletWebServerFactory(它继承了WebServerFactory接口)进行配置
// ServletWebServerFactoryCustomizer实现了WebServerFactoryCustomizer接口
// ConfigurableServletWebServerFactory继承了WebServerFactory接口
// 之所以强调这些,因为在 注4 总会用到哦
public class ServletWebServerFactoryCustomizer implements
		WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

	private final ServerProperties serverProperties;

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

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

	@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);
	}
  • 注3:实例化一个 TomcatServletWebServerFactoryCustomizer的bean,它对TomcatServletWebServerFactory(它是WebServerFactory的一个实现类)进行配置
// TomcatServletWebServerFactoryCustomizer实现了WebServerFactoryCustomizer接口
// TomcatServletWebServerFactory实现了WebServerFactory接口
// 在 注4 中会用到哦
public class TomcatServletWebServerFactoryCustomizer
		implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>, Ordered {

	private final ServerProperties serverProperties;

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

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

	@Override
	public void customize(TomcatServletWebServerFactory factory) {
		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());
		}
	}
  • 注4:通过@import引入BeanPostProcessorsRegistrar,进而通过BeanPostProcessorsRegistrar确保实例化一个WebServerFactoryCustomizerBeanPostProcessor实例bean,这个BeanPostProcessor的作用其实跟1.x版本中的EmbeddedServletContainerCustomizerBeanPostProcessor作用是一样的(摘抄部分源码如下),
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName)
			throws BeansException {
        // 当bean是WebServerFactory的实例时则进行postProcessBeforeInitialization处理
        // 在注1中我们实例化了一个TomcatServletWebServerFactory,在这里可以派上用场了
        //都是实现或继承了webServerFactory
		if (bean instanceof WebServerFactory) {
			postProcessBeforeInitialization((WebServerFactory) bean);
		}
		return bean;
	}


	@SuppressWarnings("unchecked")
	private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
		   // 使用WebServerFactoryCustomizer的customize方法对webServerFactory进行配置,

           LambdaSafe
				.callbacks(WebServerFactoryCustomizer.class, getCustomizers(),
						webServerFactory)
				.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
				.invoke((customizer) -> customizer.customize(webServerFactory));
	}

	private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
		if (this.customizers == null) {
			// Look up does not include the parent context
			this.customizers = new ArrayList<>(getWebServerFactoryCustomizerBeans());
            // 对所有的WebServerFactoryCustomizer按照Orderd进行排序
			this.customizers.sort(AnnotationAwareOrderComparator.INSTANCE);
			this.customizers = Collections.unmodifiableList(this.customizers);
		}
		return this.customizers;
	}

    // 从beanFactory中找到所有的WebServerFactoryCustomizer实例bean
    // 步骤(3)中 EmbeddedWebServerFactoryCustomizerAutoConfiguration
    //实例化了一个TomcatWebServerFactoryCustomizer的bean,
    //这个bean实现了WebServerFactoryCustomizer接口,
    // 在注2和注3中ServletWebServerFactoryAutoConfiguration实例化的 
    //ServletWebServerFactoryCustomizer和TomcatServletWebServerFactoryCustomizer
    //都实现了WebServerFactoryCustomizer接口,
   //因此在这里至少有3个我们已经知道的WebServerFactoryCustomizer可以在这里找到
	private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
		return (Collection) this.beanFactory
				.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
	}

         对于上面的 注1~ 注4,都出现了WebServerFactory或它的子类,我们可以用下面这张类图来阐述他们的关系:TomcatServletWebServerFactory实现了ConfigurableTomcatWebServerFactory接口,而ConfigurableTomcatWebServerFactory接口又继承了WebServerFactory接口

          

  (5) 跟1.x版本中的情况一样,以上步骤的主要目的就是实例化一个TomcatServletWebServerFactory,然后通过各个WebServerFactoryCustomizer对这个factory进行定制,最终得到一个完整的TomcatServletWebServerFactory,然后它的getWebServer方法就得到了一个tomcat实例,至此tomcat的实例过程讲解完毕。

     最后我们再总结一下对于spring-boot v1.x版本和v2.x版本,tomcat的实例化过程的具体区别

  •  WebServerFactoryCustomizerBeanPostProcessor替代了EmbeddedServletContainerCustomizerBeanPostProcessor
  •  WebServerFactory及其子类替代了ConfigurableEmbeddedServletContainer及其子类
  •  WebServerFactoryCustomizer及其子类替代了EmbeddedServletContainerCustomizer及其子类
  •  ServerProperties在2.x中只是一个普通的配置类,而在1.x中它比较复杂,如下图是它的类关系图,它还是EmbeddedServletContainerCustomizer的实现类,并且会作为一个默认实例化的bean起作用,在2.x中ServerProperties主要是作为各个Customizer的构造参数,然后在customize方法中使用。

猜你喜欢

转载自blog.csdn.net/song_java/article/details/86539380