tomcat集成源码:
SpringBoot默认情况下,集成了tomcat。其源码如下:
1:在spring-boot-autoconfigure包的spring.factories里,配置了tomcat启动的依赖项,代码如下,这里比较重要的是EmbeddedServletContainerAutoConfiguration和ServerPropertiesAutoConfiguration:
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpEncodingAutoConfiguration,\
org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration,\
org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration,\
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration,\
2:在 EmbeddedServletContainerAutoConfiguration 这个自动配置类里,如果存在tomcat 和 servlet 类,则注册 TomcatEmbeddedServletContainerFactory 实例对象。代码如下:
@Configuration
@ConditionalOnClass({ Servlet.class, Tomcat.class })
@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
@Bean
public TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {
return new TomcatEmbeddedServletContainerFactory();
}
}
同时,import引入 BeanPostProcessorsRegistrar 配置,在该类里,引入EmbeddedServletContainerCustomizerBeanPostProcessor 和 ErrorPageRegistrarBeanPostProcessor 两个后置处理器。
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (this.beanFactory == null) {
return;
}
registerSyntheticBeanIfMissing(registry,
"embeddedServletContainerCustomizerBeanPostProcessor",
EmbeddedServletContainerCustomizerBeanPostProcessor.class);
registerSyntheticBeanIfMissing(registry,
"errorPageRegistrarBeanPostProcessor",
ErrorPageRegistrarBeanPostProcessor.class);
}
3:在 EmbeddedServletContainerCustomizerBeanPostProcessor 的 postProcessBeforeInitialization 方法里,判断bean实例是不是ConfigurableEmbeddedServletContainer 类型(TomcatEmbeddedServletContainerFactory 实现了该接口),如果是,则调用 IOC容器中 EmbeddedServletContainerCustomizer 类型的实例进行配置客户定义的值,代码如下:
private void postProcessBeforeInitialization(
ConfigurableEmbeddedServletContainer bean) {
for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {
customizer.customize(bean);
}
}
说明:在ServerPropertiesAutoConfiguration自动实例化的 ServerProperties 实例就实现了接口:EmbeddedServletContainerCustomizer。
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties
implements EmbeddedServletContainerCustomizer, EnvironmentAware, Ordered {
4:在ServerProperties的customize 方法里面,会使用在配置文件中以server.开头的配置覆盖默认值。
public void customize(ConfigurableEmbeddedServletContainer container) {
if (getPort() != null) {
container.setPort(getPort());
}
if (getAddress() != null) {
container.setAddress(getAddress());
}
if (getContextPath() != null) {
container.setContextPath(getContextPath());
}
if (getDisplayName() != null) {
container.setDisplayName(getDisplayName());
}
if (getSession().getTimeout() != null) {
container.setSessionTimeout(getSession().getTimeout());
}
5:在SpringBoot的启动核心方法refresh方法中,会调用onfresh方法。 EmbeddedWebApplicationContext的该方法会 调用 createEmbeddedServletContainer 方法进行初始化tomcat,代码如下:
private void createEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
ServletContext localServletContext = getServletContext();
if (localContainer == null && localServletContext == null) {
EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();
this.embeddedServletContainer = containerFactory
.getEmbeddedServletContainer(getSelfInitializer());
}
else if (localServletContext != null) {
try {
getSelfInitializer().onStartup(localServletContext);
}
6:在这里,方法 getEmbeddedServletContainerFactory 得到的实际是 TomcatEmbeddedServletContainerFactory 实例对象。getEmbeddedServletContainer 方法的实现如下:
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);
}
7:tomcat的结构层次是:Server --> Service --> Engine --> Host --> Context。在初始化中,Server的对象是:StandardServer。 Service的对象是:StandardService。Engine的对象是:StandardEngine。Host对象的是:StandardHost。Context对象是:TomcatEmbeddedContext。Context的配置代码如下:
protected void prepareContext(Host host, ServletContextInitializer[] initializers) {
File docBase = getValidDocumentRoot();
docBase = (docBase != null ? docBase : createTempDir("tomcat-docbase"));
final TomcatEmbeddedContext context = new TomcatEmbeddedContext();
context.setName(getContextPath());
context.setDisplayName(getDisplayName());
context.setPath(getContextPath());
context.setDocBase(docBase.getAbsolutePath());
......
8:tomcat创建成功后,把tomcat当做参数创建TomcatEmbeddedServletContainer,然后在TomcatEmbeddedServletContainer#initialize 里调用tomcat的start方法。
9:在spring启动过程的核心方法refresh会调用finishRefresh方法,这个方法里会调用 startEmbeddedServletContainer 方法,这里会调用start方法以启动Connector。代码如下:
private EmbeddedServletContainer startEmbeddedServletContainer() {
EmbeddedServletContainer localContainer = this.embeddedServletContainer;
if (localContainer != null) {
localContainer.start();
}
return localContainer;
}