spring-boot-autoconfigure包下META-INF文件下的spring-autoconfigure-metadata.properties文件指出自动配置类的加载前后顺序以及条件.
META-INF文件下还有一个spring.factories,里面将所有springboot的自动配置类涵盖在里面了.springboot启动的时候会去加载该文件,然后根据自动配置类的条件注解是否满足选择将相应的Bean注入到Spring容器中. 以上并非本文的重点,上面的内容后续可以整理成一篇单独的博客.
让我们回到本文的主角ServletWebServerFactoryAutoConfiguration.
ServletWebServerFactoryAutoConfiguration在spring.factories中能被找到.
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 导入依赖行
/**
* EnableAutoConfiguration Auto-configuration for servlet web servers.
*
*/
@Configuration
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
// 仅在类 ServletRequest 存在于 classpath 上时才生效(javax.servlet.ServletRequest,需要导入tomcat相关包org.apache.tomcat.embed:tomcat-embed-core)
@ConditionalOnClass(ServletRequest.class)
// 仅在当前应用是 Servlet Web 应用时才生效(关于ConditionalOnWebApplication注解的源码后续单独开博文描述)
@ConditionalOnWebApplication(type = Type.SERVLET)
// 确保yml配置文件中前缀为 server 的配置参数加载到 bean ServerProperties
@EnableConfigurationProperties(ServerProperties.class)
// 1. 通过ImportBeanDefinitionRegistrar的实现类方式导入 ServletWebServerFactoryAutoConfiguration.
// BeanPostProcessorsRegistrar 以注册
// BeanPostProcessor : WebServerFactoryCustomizerBeanPostProcessor 和
// ErrorPageRegistrarBeanPostProcessor
// 2. 直接导入 EmbeddedTomcat/EmbeddedJetty/EmbeddedUndertow 这三个属于
// ServletWebServerFactoryConfiguration 的嵌套配置类,这三个配置类会分别检测
// classpath上存在的类,从而判断当前应用使用的是 Tomcat/Jetty/Undertow,
// 从而决定定义哪一个 Servlet Web服务器的工厂 bean :
// TomcatServletWebServerFactory/JettyServletWebServerFactory/UndertowServletWebServerFactory
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
// 定义 bean ServletWebServerFactoryCustomizer
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
//根据serverProperties的自定义配置创建一个ServletWebServerFactoryCustomizer
//主要设置Port,Address,,Compression,ServerHeader,ContextParameters等参数
return new ServletWebServerFactoryCustomizer(serverProperties);
}
// 针对当前Servlet容器是Tomcat时定义该 bean,用于定制化 TomcatServletWebServerFactory
@Bean
// 仅在类 org.apache.catalina.startup.Tomcat 存在于 classpath 上时才生效,
//需要导入tomcat相关包org.apache.tomcat.embed:tomcat-embed-core
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
//根据serverProperties的自定义配置创建一个TomcatServletWebServerFactoryCustomizer
//主要用于设置Tomcat相关的参数比如additionalTldSkipPatterns,redirectContextRoot,
//useRelativeRedirects
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
/**
* Registers a WebServerFactoryCustomizerBeanPostProcessor. Registered via
* ImportBeanDefinitionRegistrar for early registration.
* 这是一个 ImportBeanDefinitionRegistrar(参见@Import注解的三种用法),
* 它会向容器注入两个 BeanPostProcessor :
* 1. WebServerFactoryCustomizerBeanPostProcessor
* 该 BeanPostProcessor 会搜集容器中所有的 WebServerFactoryCustomizer,对当前应用所采用的
* WebServerFactory 被初始化前进行定制
* 2. ErrorPageRegistrarBeanPostProcessor
* 该 BeanPostProcessor 会搜集容器中所有的 ErrorPageRegistrar,添加到当前应用所采用的
* ErrorPageRegistry 中,实际上,这里的 ErrorPageRegistry 会是 ConfigurableWebServerFactory,
* 具体实现上来讲,是一个 ConfigurableTomcatWebServerFactory,ConfigurableJettyWebServerFactory
* 或者 ConfigurableUndertowWebServerFactory,分别对应 Tomcat, Jetty, Undertow 这三种
* Servlet Web 容器的工厂类
*/
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;
}
registerSyntheticBeanIfMissing(registry,
"webServerFactoryCustomizerBeanPostProcessor",
WebServerFactoryCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry,
String name, Class<?> beanClass) {
//spring容器中不存在WebServerFactoryCustomizerBeanPostProcessor实例情况下注入
if (ObjectUtils.isEmpty(
this.beanFactory.getBeanNamesForType(beanClass, true, false))) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass);
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(name, beanDefinition);
}
}
}
}
ServletWebServerFactoryConfiguration
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 导入依赖行
class ServletWebServerFactoryConfiguration {
@Configuration
//pom.xml中引入了spring-boot-starter-web启动器会导入tomcat包,以下条件得到满足
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
//创建了一个TomcatServletWebServerFactory注入到spring容器中,
//后面讲述springboot如何内嵌一个Tomcat服务时会讲到这个类
@Bean
public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
return new TomcatServletWebServerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
//pom.xml中引入了spring-boot-starter-web启动器会导入tomcat包,以下条件不满足
//缺少Server,Loader,WebAppContext
@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,
WebAppContext.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyServletWebServerFactory JettyServletWebServerFactory() {
return new JettyServletWebServerFactory();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
//pom.xml中引入了spring-boot-starter-web启动器会导入tomcat包,以下条件不满足
//缺少Undertow,SslClientAuthMode
@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
return new UndertowServletWebServerFactory();
}
}
}
ServletWebServerFactoryCustomizer
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 导入依赖行
public class ServletWebServerFactoryCustomizer implements
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
private final ServerProperties serverProperties;
public ServletWebServerFactoryCustomizer(ServerProperties serverProperties) {
//yml文件中自定义配置
this.serverProperties = serverProperties;
}
@Override
public int getOrder() {
return 0;
}
//配置相关属性,该方法的调用在WebServerFactoryCustomizerBeanPostProcessor中的生命周期钩子时被触发
@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);
}
}
TomcatServletWebServerFactoryCustomizer
package org.springframework.boot.autoconfigure.web.servlet;
// 省略 import 导入依赖行
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());
}
}
//addContextCustomizers(TomcatContextCustomizer tomcatContextCustomizer)
//涉及到tomcat的知识,暂未了解
private void customizeRedirectContextRoot(ConfigurableTomcatWebServerFactory factory,
boolean redirectContextRoot) {
factory.addContextCustomizers((context) -> context
.setMapperContextRootRedirectEnabled(redirectContextRoot));
}
//addContextCustomizers(TomcatContextCustomizer tomcatContextCustomizer)
//涉及到tomcat的知识,暂未了解
private void customizeUseRelativeRedirects(ConfigurableTomcatWebServerFactory factory,
boolean useRelativeRedirects) {
factory.addContextCustomizers(
(context) -> context.setUseRelativeRedirects(useRelativeRedirects));
}
}
WebServerFactoryCustomizerBeanPostProcessor
// 省略 import 导入依赖行
package org.springframework.boot.web.server;
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;
}
//生命周期钩子,在spring容器启动后会被调用
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof WebServerFactory) {
//执行下面的postProcessBeforeInitialization方法
postProcessBeforeInitialization((WebServerFactory) bean);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@SuppressWarnings("unchecked")
private void postProcessBeforeInitialization(WebServerFactory webServerFactory) {
LambdaSafe
//执行下面的getCustomizers方法
.callbacks(WebServerFactoryCustomizer.class, getCustomizers(),
webServerFactory)
.withLogger(WebServerFactoryCustomizerBeanPostProcessor.class)
.invoke((customizer) -> customizer.customize(webServerFactory));
}
private Collection<WebServerFactoryCustomizer<?>> getCustomizers() {
if (this.customizers == null) {
//执行下面的getWebServerFactoryCustomizerBeans方法
// 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;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private Collection<WebServerFactoryCustomizer<?>> getWebServerFactoryCustomizerBeans() {
//获取到我们在上面注入的WebServerFactoryCustomizer的两个子类ServletWebServerFactoryCustomizer,
//TomcatServletWebServerFactoryCustomizer
return (Collection) this.beanFactory
.getBeansOfType(WebServerFactoryCustomizer.class, false, false).values();
}
}
总结:如果我们在开发中是servlet环境,且引入了tomcat相关包org.apache.tomcat.embed:tomcat-embed-core(spring-boot-starter-web->spring-boot-starter-tomcat)
ServletWebServerFactoryAutoConfiguration自动配置类会注入WebServerFactoryCustomizer的两个子类ServletWebServerFactoryCustomizer和TomcatServletWebServerFactoryCustomizer,同时会经由@Import注入ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class的方式将WebServerFactoryCustomizerBeanPostProcessor注入到容器中,正是WebServerFactoryCustomizerBeanPostProcessor的生命周期钩子中调用了WebServerFactoryCustomizer的自定义函数,实现对servlet,tomcat容器的自定义化.