title: 【SpringBoot】Servlet容器
date: 2017-08-31 21:25:12
tags:
- Java
- Spring
categories: Spring
記得自己看 Spring Boot 源碼的初衷是對(duì)部署時(shí)不需要額外的 Servlet 容器的好奇,好像看著看著關(guān)注到了其他細(xì)節(jié)。挖了幾個(gè)坑就跳過(guò)了,今天把之前關(guān)于 Spring Boot 與 Servlet 容器的坑填一下。
先回(rang)顧(wo)一(xiang)下(xiang)之前與 Web 環(huán)境相關(guān)的內(nèi)容:
- SpringBoot包文件執(zhí)行分析,這里說(shuō)到開(kāi)啟了新線程調(diào)用應(yīng)用入口,該線程設(shè)置了上下文類加載器 LaunchedURLClassLoader
- 【SpringBoot】SpringApplication實(shí)例創(chuàng)建,這里說(shuō)到根據(jù) CLASSPTH 的包含的類推斷當(dāng)前是否是 web 環(huán)境
- 【SpringBoot】容器啟動(dòng),這里說(shuō)到根據(jù)是否 web 環(huán)境創(chuàng)建做相關(guān)準(zhǔn)備,創(chuàng)建處理 web 環(huán)境對(duì)應(yīng)的 Spring容器
- 【Spring容器刷新】,這里說(shuō)到 Spring 容器生命周期的相關(guān)方法
Servlet 容器啟動(dòng)
【SpringBoot】容器啟動(dòng) 中提到的創(chuàng)建處理 web 環(huán)境對(duì)應(yīng)的 Spring 容器實(shí)際創(chuàng)建的就是 AnnotationConfigEmbeddedWebApplicationContext,這個(gè)類是 ApplicationContext 的子類。其分別在 onRefresh 和 finishRefresh 方法中創(chuàng)建和啟動(dòng) Servlet 容器:
@Override
protected void onRefresh() {
super.onRefresh();
try {
createEmbeddedServletContainer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start embedded container", ex);
}
}
@Override
protected void finishRefresh() {
super.finishRefresh();
EmbeddedServletContainer localContainer = startEmbeddedServletContainer();
if (localContainer != null) {
publishEvent(
new EmbeddedServletContainerInitializedEvent(this, localContainer));
}
}
在 Spring 容器生命周期里與 Servlet 容器相關(guān)的邏輯封裝在以上兩個(gè)方法,分別用以創(chuàng)建和啟動(dòng) Servlet 容器。
Servlet 容器創(chuàng)建細(xì)節(jié)
上面說(shuō)到 AnnotationConfigEmbeddedWebApplicationContext 中創(chuàng)建 Servlet 容器,具體的細(xì)節(jié)如下:
// AnnotationConfigEmbeddedWebApplicationContext
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
if (localContainer == null && localServletContext == null) {
// 獲取 Servlet 容器工廠
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
// 獲取 Servlet 容器初始化器
// 使用 Servlet 容器初始化器創(chuàng)建 Servlet 容器
this.embeddedServletContainer =
containerFactory.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context",
ex);
}
}
initPropertySources();
}
細(xì)節(jié)可以分為:
- 獲取 Servlet 容器工廠
- 獲取 Servlet 容器初始化器
- 創(chuàng)建 Servlet 容器
獲取 Servlet 容器工廠
// AnnotationConfigEmbeddedWebApplicationContext
protected EmbeddedServletContainerFactory getEmbeddedServletContainerFactory() {
// Use bean names so that we don't consider the hierarchy
String[] beanNames = getBeanFactory()
.getBeanNamesForType(EmbeddedServletContainerFactory.class);
// 省略異常
return getBeanFactory().getBean(beanNames[0],
EmbeddedServletContainerFactory.class);
}
直接從 Spring 容器里獲取 Servlet 容器工廠。一時(shí)之間卡住了不知道 EmbeddedServletContainerFactory 這個(gè)類時(shí)怎么注冊(cè)到 Spring 容器中的。在網(wǎng)上查了一下發(fā)現(xiàn)是 META-INF/spring.factories 里指定了 EmbeddedServletContainerAutoConfiguration 這個(gè)配置類。而 EmbeddedServletContainerFactory 是 EmbeddedServletContainerAutoConfiguration 這個(gè)自動(dòng)化配置類中被注冊(cè)到 Spring 容器中的,關(guān)于配置類的注冊(cè)我又要挖坑了。EmbeddedServletContainerAutoConfiguration:
@AutoConfigureOrder(-2147483648)
@Configuration
@ConditionalOnWebApplication // 在Web環(huán)境下起作用
@Import({EmbeddedServletContainerAutoConfiguration.BeanPostProcessorsRegistrar.class})
public class EmbeddedServletContainerAutoConfiguration {
public EmbeddedServletContainerAutoConfiguration() {
}
// 在 import 中導(dǎo)入該類
// 主要作用是注冊(cè) EmbeddedServletContainerCustomizerBeanPostProcessor,
// ErrorPageRegistrarBeanPostProcessor
public static class BeanPostProcessorsRegistrar
implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
// 省略
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if(this.beanFactory != null) {
// 注冊(cè) EmbeddedServletContainerCustomizerBeanPostProcessor
this.registerSyntheticBeanIfMissing(
registry, "embeddedServletContainerCustomizerBeanPostProcessor",
EmbeddedServletContainerCustomizerBeanPostProcessor.class);
// 注冊(cè) ErrorPageRegistrarBeanPostProcessor
this.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);
}
}
}
// 省略 Jetty,Undertow 配置
@Configuration
@ConditionalOnClass({Servlet.class, Tomcat.class})
@ConditionalOnMissingBean(
value = {EmbeddedServletContainerFactory.class},
search = SearchStrategy.CURRENT
)
public static class EmbeddedTomcat {
public EmbeddedTomcat() {
}
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
// 注冊(cè) EmbeddedServletContainerFactory 的實(shí)現(xiàn)類
return new TomcatEmbeddedServletContainerFactory();
}
}
}
當(dāng)滿足特定條件時(shí)會(huì)注冊(cè)具體的 EmbeddedServletContainerFactory 實(shí)現(xiàn)類,例如 TomcatEmbeddedServletContainerFactory。
這里還看到 注冊(cè)了 EmbeddedServletContainerCustomizerBeanPostProcessor 和 ErrorPageRegistrarBeanPostProcessor 。簡(jiǎn)單看了一下 EmbeddedServletContainerCustomizerBeanPostProcessor,這是一個(gè)基本的 BeanPostProcessor,具體作用是對(duì) EmbeddedServletContainerCustomizer 的實(shí)例進(jìn)行定制,具體的實(shí)現(xiàn)包括:ErrorPageCustomizer,TomcatWebSocketContainerCustomizer,ServerProperties 等。
// EmbeddedServletContainerCustomizerBeanPostProcessor
public class EmbeddedServletContainerCustomizerBeanPostProcessor
implements BeanPostProcessor, BeanFactoryAware {
private ListableBeanFactory beanFactory;
private List<EmbeddedServletContainerCustomizer> customizers;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof ConfigurableEmbeddedServletContainer) {
// 處理ConfigurableEmbeddedServletContainer類型的bean
postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);
}
return bean;
}
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
// 對(duì)ConfigurableEmbeddedServletContainer類型的bean定制化處理
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {
if (this.customizers == null) {
// 從容器中找出所有EmbeddedServletContainerCustomizer類型的bean
this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(
this.beanFactory.getBeansOfType(EmbeddedServletContainerCustomizer.class,
false, false).values());
Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);
this.customizers = Collections.unmodifiableList(this.customizers);
}
return this.customizers;
}
}
Servlet 容器初始化器
再回顧一下 Servlet 容器的創(chuàng)建核心邏輯:
containerFactory.getEmbeddedServletContainer(getSelfInitializer());
先獲取 Servlet 初始化器,然后創(chuàng)建 Servlet 容器
private org.springframework.boot.web.servlet.ServletContextInitializer getSelfInitializer() {
return new ServletContextInitializer() {
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
selfInitialize(servletContext);
}
};
}
private void selfInitialize(ServletContext servletContext) throws ServletException {
// Servlet 容器準(zhǔn)備
prepareEmbeddedWebApplicationContext(servletContext);
// 初始 scopes
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
ExistingWebApplicationScopes existingScopes = new ExistingWebApplicationScopes(
beanFactory);
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory,
getServletContext());
existingScopes.restore();
// 注冊(cè) web 相關(guān) bean
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory,
getServletContext());
// 初始化 servlet, filter, Listener 并注冊(cè)
for (ServletContextInitializer beans : getServletContextInitializerBeans()) {
beans.onStartup(servletContext);
}
}
// 獲取 ServletContext 初始化 bean
protected Collection<ServletContextInitializer> getServletContextInitializerBeans() {
new ServletContextInitializerBeans(getBeanFactory());
}
public ServletContextInitializerBeans(ListableBeanFactory beanFactory) {
this.initializers = new LinkedMultiValueMap<Class<?>, ServletContextInitializer>();
// 添加 ServletContextInitializer 類型的 bean
addServletContextInitializerBeans(beanFactory);
addAdaptableBeans(beanFactory);
List<ServletContextInitializer> sortedInitializers =
new ArrayList<ServletContextInitializer>();
for (Map.Entry<?, List<ServletContextInitializer>> entry : this.initializers.entrySet()) {
AnnotationAwareOrderComparator.sort(entry.getValue());
sortedInitializers.addAll(entry.getValue());
}
this.sortedList = Collections.unmodifiableList(sortedInitializers);
}
private void addServletContextInitializerBeans(ListableBeanFactory beanFactory) {
for (Entry<String, ServletContextInitializer> initializerBean : getOrderedBeansOfType(
beanFactory, ServletContextInitializer.class)) {
addServletContextInitializerBean(initializerBean.getKey(),
initializerBean.getValue(), beanFactory);
}
}
private void addServletContextInitializerBean(String beanName,
ServletContextInitializer initializer, ListableBeanFactory beanFactory) {
if (initializer instanceof ServletRegistrationBean) {
// servlet
Servlet source = ((ServletRegistrationBean) initializer).getServlet();
addServletContextInitializerBean(Servlet.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof FilterRegistrationBean) {
// filter
Filter source = ((FilterRegistrationBean) initializer).getFilter();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof DelegatingFilterProxyRegistrationBean) {
// filter
String source = ((DelegatingFilterProxyRegistrationBean) initializer)
.getTargetBeanName();
addServletContextInitializerBean(Filter.class, beanName, initializer,
beanFactory, source);
}
else if (initializer instanceof ServletListenerRegistrationBean) {
// listener
EventListener source = ((ServletListenerRegistrationBean<?>) initializer)
.getListener();
addServletContextInitializerBean(EventListener.class, beanName, initializer,
beanFactory, source);
}
else {
addServletContextInitializerBean(ServletContextInitializer.class, beanName,
initializer, beanFactory, initializer);
}
}
創(chuàng)建 Servlet 容器
以 TomcatEmbeddedServletContainerFactory 的創(chuàng)建容器方法為例:
@Override
public EmbeddedServletContainer getEmbeddedServletContainer(
ServletContextInitializer... initializers) {
Tomcat tomcat = new 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);
return getTomcatEmbeddedServletContainer(tomcat);
}
上面的代碼完成了 Servlet 容器啟動(dòng)前所有的創(chuàng)建,配置動(dòng)作。
Servlet 容器啟動(dòng)
private EmbeddedServletContainer startEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
if (localContainer != null) {
localContainer.start();
}
return localContainer;
}
啟動(dòng)的邏輯并不復(fù)雜,直接調(diào)用 Servlet 容器的 start 方法。
總結(jié)
Spring Boot 使用的內(nèi)嵌 Servlet 容器啟動(dòng)過(guò)程:
- 從 spring.factories 中讀取并注冊(cè)了 EmbeddedServletContainerAutoConfiguration 類
- EmbeddedServletContainerAutoConfiguration 注冊(cè)了 Servlet 容器工廠類
- 在 Spring 容器生命周期的 onRefresh 方法中開(kāi)始創(chuàng)建 Servlet 容器
- 獲取 Servlet 容器工廠
- 獲取 Servlet 相關(guān)初始化 bean
- 配置并創(chuàng)建 Servlet 容器
- 在 Spring 容器生命周期的 finishRefresh 方法中調(diào)用 Servlet 容器的 start 方法啟動(dòng)容器