SpringBoot嵌入式Servlet容器自动配置原理
EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置类
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication // Web应用下自动配置才会生效
@Import(BeanPostProcessorsRegistrar.class) // 导入BeanPostProcessorsRegistrar
// 导入了EmbeddedServletContainerCustomizerBeanPostProcessor:
// BeanPostProcessor:后置处理器:bean初始化前后(创建完对象,还没属性赋值)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class }) // 容器中引入了Tomcat依赖配置才会生效
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT) // 容器中没有用户自定义的EmbeddedServletContainerFactory(嵌入式Servlet容器工厂)才会生效
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory(){
return new TomcatEmbeddedServletContainerFactory();
}
}
// 下面Jetty和Undertow同理,根据容器中导入的依赖,来导入不同的Servlet容器工厂
@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();
}
}
@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();
}
}
}
- EmbeddedServletContainerAutoConfiguration:嵌入式Servlet容器工厂类
package org.springframework.boot.context.embedded;
import org.springframework.boot.web.servlet.ServletContextInitializer;
// 获取嵌入式的Servlet容器
public interface EmbeddedServletContainerFactory {
EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... var1);
}
从类关系图中可以看到有三种Servlet容器工厂
- EmbeddedServletContainer:嵌入式Servlet容器
对应的Servlet容器也是三种
以Tomcat为例分析:如果导入了Tomcat依赖,并且没有自定义Servlet内置容器,SpringBoot则会自动注入一个TomcatEmbeddedServletContainerFactory(在上面的代码中可以看出)
// AbstractEmbeddedServletContainerFactory类部分代码
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
// 创建Tomcat
Tomcat tomcat = new 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);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
// 传入配置好的Tomcat,返回一个嵌入式Servlet容器,并启动Tomcat服务器
return getTomcatEmbeddedServletContainer(tomcat);
}
对嵌入式容器的配置修改是如何生效
EmbeddedServletContainerCustomizer:定制器帮我们修改了Servlet容器的配置?
容器中导入了BeanPostProcessorsRegistrar(类中的注解@Import),在这中间又导入了EmbeddedServletContainerCustomizerBeanPostProcessor
// EmbeddedServletContainerCustomizerBeanPostProcessor部分代码
// 初始化之前
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
// 如果当前初始化的是一个ConfigurableEmbeddedServletContainer类型的组件
if (bean instanceof ConfigurableEmbeddedServletContainer) {
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
// 获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值;
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// Look up does not include the parent context
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory
//从容器中获取所有这个类型的组件:EmbeddedServletContainerCustomizer
//定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件
.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false)
.values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
步骤总结:
1)、SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory【TomcatEmbeddedServletContainerFactory】
2)、容器中某个组件要创建对象就会惊动后置处理器;EmbeddedServletContainerCustomizerBeanPostProcessor;只要是嵌入式的Servlet容器工厂,后置处理器就工作;
3)、后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法