在spring-boot-autoconfigure包中有个web模块:
该模块下有个类EmbeddedWebServerFactoryCustomizerAutoConfiguration,负责嵌入式Servlet容器的自动配置,该类的源码:
@Configuration
@EnableConfigurationProperties(ServerProperties.class)
public class EmbeddedWebServerFactoryCustomizerAutoConfiguration {
@ConditionalOnClass({ Tomcat.class, UpgradeProtocol.class })//判断是否引入了Tomcat依赖,我们默认就是引入的Tomcat
public static class TomcatWebServerFactoryCustomizerConfiguration {
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
}
/**
* Nested configuration if Jetty is being used.
*/
@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);
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({ Undertow.class, SslClientAuthMode.class })
public static class UndertowWebServerFactoryCustomizerConfiguration {
@Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(
Environment environment, ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}
}
}
该类中有三个方法:TomcatWebServerFactoryCustomizerConfiguration、JettyWebServerFactoryCustomizerConfiguration、UndertowWebServerFactoryCustomizerConfiguration,这三个方法中都有一个注解@ConditionalOnClass,该注解中标明在引入哪些依赖时就会使相应的XxxCustomizerConfiguration生效,这也是通过修改依赖就可将Servlet容器切换为Tomcat、Jetty和Undertow的原因
在旧版本的SpringBoot中,会有些不同:
旧版本的web模块下有个EmbeddedServletContainerAutoConfiguration:负责嵌入式Servlet容器的自动配置
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
//后置处理器:bean初始化前后(创建完对象,还没赋值赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})//判断当前是否引入了Tomcat依赖;
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
//判断当前容器没有用户自己定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Jetty is being used.
*/
@Configuration
@ConditionalOnClass({Servlet.class, Server.class, Loader.class, WebAppContext.class})
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedJetty {
@Bean
public JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {
return new JettyEmbeddedServletContainerFactory();
}
}
/**
* Nested configuration if Undertow is being used.
*/
@Configuration
@ConditionalOnClass({Servlet.class, Undertow.class, SslClientAuthMode.class})
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedUndertow {
@Bean
public UndertowEmbeddedServletContainerFactory
undertowEmbeddedServletContainerFactory() {
return new UndertowEmbeddedServletContainerFactory();
}
}
}
EmbeddedServletContainerFactory(嵌入式Servlet容器工厂):
public interface EmbeddedServletContainerFactory {
//获取嵌入式的Servlet容器
EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers);
}
EmbeddedServletContainerFactory的实现类:
EmbeddedServletContainer(嵌入式的Servlet容器):
以TomcatEmbeddedServletContainerFactory为例:
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat(); //构建tomcat实例
//配置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);
tomcat.getEngine().setBackgroundProcessorDelay(-1);
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
//将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器
return getTomcatEmbeddedServletContainer(tomcat);
}
我们对嵌入式容器的配置修改是怎么生效?通过ServerProperties、EmbeddedServletContainerCustomizer,而ServerProperties是EmbeddedServletContainerCustomizer的子类,修改的原理,因为导入了了EmbeddedServletContainerCustomizerBeanPostProcessor,属性赋值是在该类中进行的
步骤:
1、SpringBoot根据导入的依赖情况,给容器中添加相应的
EmbeddedServletContainerFactory(如TomcatEmbeddedServletContainerFactory)
2、容器中某个组件要创建对象就会惊动后置处理器EmbeddedServletContainerCustomizerBeanPostProcessor(只要是嵌入式的Servlet容器工厂,后置处理器就工作)
3、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法给容器的属性赋值