1、获取SpringBoot内置Tomcat自动配置类:
在SpringBoot项目中引入spring-boot-starter-web依赖,就默认使用Tomcat容器,该依赖中引入spring-boot-starter-tomcat、spring-webmvc,就引入了tomtcat核心依赖和springMvc相关jar包,这样就间接地引入了tomcat。
在执行SpringBoot项目启动类的main()方法,启动SpringBoot项目的过程中会加载各个jar包下META-INF/spring.factories的文件,在该文件中包含着自动配置的子路径,在refresh()方法中的invokeBeanFactoryPostProcessors()中首先会对启动类上的 @SpringBootApplication 注解进行解析,最终调用 AutoConfigurationImportSelector类中的 getAutoConfigurationEntry() 加载 META-INF/spring.factories 文件中的自动配置类,得到自动配置类的全路径,其中 org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration 为tomcat自动配置类。
具体加载流程见: springBoot-启动原理
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 1、得到META-INF/spring.factories文件中配置的所有自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 移除重复的配置类
configurations = removeDuplicates(configurations);
// 获取需要排除的自动配置类,eg:注解属性中的exculde的配置类
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查需要被排除的配置类,因为有些不是自动配置类,需要抛异常
checkExcludedClasses(configurations, exclusions);
// 移除需要排除的配置类
configurations.removeAll(exclusions);
// 根据 META-INF/spring-autoconfigure-metadata.properties 中配置的规则过虑掉一部分配置类(根据@ConditionalOnXXX注解进行过滤)
configurations = getConfigurationClassFilter().filter(configurations);
// 获取符合条件的配置类后,触发 AutoConfigurationImportEvent 事件
fireAutoConfigurationImportEvents(configurations, exclusions);
// 将符合条件和需要排除的配置类封装进 AutoConfigurationEntry 对象中返回
return new AutoConfigurationEntry(configurations, exclusions);
}
2、ServletWebServerFactoryAutoConfiguration - tomcat自动配置类分析
3、创建tomcat工厂
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
static class EmbeddedTomcat {
@Bean
TomcatServletWebServerFactory tomcatServletWebServerFactory(
ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
ObjectProvider<TomcatContextCustomizer> contextCustomizers,
ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
// 创建生产tomcat的工厂
TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
factory.getTomcatConnectorCustomizers()
.addAll(connectorCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatContextCustomizers()
.addAll(contextCustomizers.orderedStream().collect(Collectors.toList()));
factory.getTomcatProtocolHandlerCustomizers()
.addAll(protocolHandlerCustomizers.orderedStream().collect(Collectors.toList()));
return factory;
}
}
4、创建tomcat容器
在SpringBoot启动过程中会调用 AbstractApplicationContext.refresh() 方法,在该方法会调用onRefresh()方法,这个方法是个模板方法,最终会交给子类实现,在使用内置tomcat的SpringBoot项目中,最终会调用 ServletWebServerApplicationContext 实现(AbstractApplicationContext是GenericWebApplicationContext,ServletWebServerApplicationContext 是GenericWebApplicationContext),最终调用ServletWebServerApplicationContext 的createWebServer()方法创建 webServer。
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Servlet.class, Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
protected void onRefresh() {
// 调用 GenericWebApplicationContext类的 onRefresh() 方法,
super.onRefresh();
try {
// 获取嵌入式的Servlet容器工厂(TomcatServletWebServerFactory),并通过工厂来获取Servlet容器
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
// 获取 Servlet容器工厂
ServletWebServerFactory factory = getWebServerFactory();
createWebServer.tag("factory", factory.getClass().toString());
// 通过Servlet容器工厂加载tomcat并启动tomcat
this.webServer = factory.getWebServer(getSelfInitializer());
createWebServer.end();
getBeanFactory().registerSingleton("webServerGracefulShutdown",
new WebServerGracefulShutdownLifecycle(this.webServer));
getBeanFactory().registerSingleton("webServerStartStop",
new WebServerStartStopLifecycle(this, this.webServer));
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
在 TomcatServletWebServerFactory 类中
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
// 实例化tomcat
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
// 设置tomcat临时工作目录
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 默认使用 org.apache.coyote.http11.Http11NioProtocol 实例化Connector
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
// 给service添加Connector
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
// 关闭热部署
tomcat.getHost().setAutoDeploy(false);
// 配置 Engine
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
// 实例化 TomcatWebServer,将 DispatcherServlet 以及一些Filter添加到Tomcat中
return getTomcatWebServer(tomcat);
}
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, getPort() >= 0, getShutdown());
}
//TomcatWebServer类的构造方法
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
Assert.notNull(tomcat, "Tomcat Server must not be null");
this.tomcat = tomcat;
this.autoStart = autoStart;
this.gracefulShutdown = (shutdown == Shutdown.GRACEFUL) ? new GracefulShutdown(tomcat) : null;
initialize();
}
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
try {
addInstanceIdToEngineName();
Context context = findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) {
// Remove service connectors so that protocol binding doesn't
// happen when the service is started.
removeServiceConnectors();
}
});
// Start the server to trigger initialization listeners
//利用LifecycleBase对这一套容器(engine,host,context及wrapper)进行启动并发布configure_start、
// before_init、after_start的lifecycleEvent等事件给相应的监听器
// 本方法并没有启动tomcat
this.tomcat.start();
// We can re-throw failure exception directly in the main thread
rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
}
catch (NamingException ex) {
// Naming is not enabled. Continue
}
// Unlike Jetty, all Tomcat threads are daemon threads. We create a
// blocking non-daemon to stop immediate shutdown
startDaemonAwaitThread();
}
catch (Exception ex) {
stopSilently();
destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", ex);
}
}
}
// Tomcat类
public void start() throws LifecycleException {
getServer();
server.start();
}
// LifecycleBase
public final synchronized void start() throws LifecycleException {
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
LifecycleState.STARTED.equals(state)) {
if (log.isDebugEnabled()) {
Exception e = new LifecycleException();
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
} else if (log.isInfoEnabled()) {
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
}
return;
}
if (state.equals(LifecycleState.NEW)) {
init();
} else if (state.equals(LifecycleState.FAILED)) {
stop();
} else if (!state.equals(LifecycleState.INITIALIZED) &&
!state.equals(LifecycleState.STOPPED)) {
invalidTransition(Lifecycle.BEFORE_START_EVENT);
}
try {
setStateInternal(LifecycleState.STARTING_PREP, null, false);
startInternal();
if (state.equals(LifecycleState.FAILED)) {
// This is a 'controlled' failure. The component put itself into the
// FAILED state so call stop() to complete the clean-up.
stop();
} else if (!state.equals(LifecycleState.STARTING)) {
// Shouldn't be necessary but acts as a check that sub-classes are
// doing what they are supposed to.
invalidTransition(Lifecycle.AFTER_START_EVENT);
} else {
setStateInternal(LifecycleState.STARTED, null, false);
}
} catch (Throwable t) {
// This is an 'uncontrolled' failure so put the component into the
// FAILED state and throw an exception.
handleSubClassException(t, "lifecycleBase.startFail", toString());
}
}
createWebServer
5、启动tomcat容器
创建webServer后在refresh()方法中的finishRefresh()完成tomcat的启动。
最终会调用 TomcatWebServer中的start()方法启动tomcat容器。
1 protected void finishRefresh() {
2 // Clear context-level resource caches (such as ASM metadata from scanning).
3 clearResourceCaches();
4
5 // Initialize lifecycle processor for this context.
6 initLifecycleProcessor();
7
8 // Propagate refresh to lifecycle processor first.
9 // 启动tomcat
10 getLifecycleProcessor().onRefresh();
11
12 // Publish the final event.
13 publishEvent(new ContextRefreshedEvent(this));
14
15 // Participate in LiveBeansView MBean, if active.
16 if (!NativeDetector.inNativeImage()) {
17 LiveBeansView.registerApplicationContext(this);
18 }
19 }
20
21 @Override
22 public void onRefresh() {
23 startBeans(true);
24 this.running = true;
25 }
26
27 private void startBeans(boolean autoStartupOnly) {
28 Map<String, Lifecycle> lifecycleBeans = getLifecycleBeans();
29 Map<Integer, LifecycleGroup> phases = new TreeMap<>();
30
31 lifecycleBeans.forEach((beanName, bean) -> {
32 if (!autoStartupOnly || (bean instanceof SmartLifecycle && ((SmartLifecycle) bean).isAutoStartup())) {
33 int phase = getPhase(bean);
34 phases.computeIfAbsent(
35 phase,
36 p -> new LifecycleGroup(phase, this.timeoutPerShutdownPhase, lifecycleBeans, autoStartupOnly)
37 ).add(beanName, bean);
38 }
39 });
40 if (!phases.isEmpty()) {
41 // 遍历启动
42 phases.values().forEach(LifecycleGroup::start);
43 }
44 }
45
46 public void start() {
47 if (this.members.isEmpty()) {
48 return;
49 }
50 if (logger.isDebugEnabled()) {
51 logger.debug("Starting beans in phase " + this.phase);
52 }
53 Collections.sort(this.members);
54 for (LifecycleGroupMember member : this.members) {
55 doStart(this.lifecycleBeans, member.name, this.autoStartupOnly);
56 }
57 }
58
59 private void doStart(Map<String, ? extends Lifecycle> lifecycleBeans, String beanName, boolean autoStartupOnly) {
60 Lifecycle bean = lifecycleBeans.remove(beanName);
61 if (bean != null && bean != this) {
62 String[] dependenciesForBean = getBeanFactory().getDependenciesForBean(beanName);
63 for (String dependency : dependenciesForBean) {
64 doStart(lifecycleBeans, dependency, autoStartupOnly);
65 }
66 if (!bean.isRunning() &&
67 (!autoStartupOnly || !(bean instanceof SmartLifecycle) || ((SmartLifecycle) bean).isAutoStartup())) {
68 if (logger.isTraceEnabled()) {
69 logger.trace("Starting bean '" + beanName + "' of type [" + bean.getClass().getName() + "]");
70 }
71 try {
72 bean.start();
73 }
74 catch (Throwable ex) {
75 throw new ApplicationContextException("Failed to start bean '" + beanName + "'", ex);
76 }
77 if (logger.isDebugEnabled()) {
78 logger.debug("Successfully started bean '" + beanName + "'");
79 }
80 }
81 }
82 }
83
84 //WebServerStartStopLifecycle 中start() 方法的实现
85 public void start() {
86 this.weServerManager.start();
87 this.running = true;
88 }
89
90 void start() {
91 this.handler.initializeHandler();
92 this.webServer.start();
93 this.applicationContext
94 .publishEvent(new ReactiveWebServerInitializedEvent(this.webServer, this.applicationContext));
95 }
96 // 完成对tomcat的启动
97 @Override
98 public void start() throws WebServerException {
99 synchronized (this.monitor) {
100 if (this.started) {
101 return;
102 }
103 try {
104 addPreviouslyRemovedConnectors();
105 Connector connector = this.tomcat.getConnector();
106 if (connector != null && this.autoStart) {
107 performDeferredLoadOnStartup();
108 }
109 checkThatConnectorsHaveStarted();
110 this.started = true;
111 logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
112 + getContextPath() + "'");
113 }
114 catch (ConnectorStartFailedException ex) {
115 stopSilently();
116 throw ex;
117 }
118 catch (Exception ex) {
119 PortInUseException.throwIfPortBindingException(ex, () -> this.tomcat.getConnector().getPort());
120 throw new WebServerException("Unable to start embedded Tomcat server", ex);
121 }
122 finally {
123 Context context = findContext();
124 ContextBindings.unbindClassLoader(context, context.getNamingToken(), getClass().getClassLoader());
125 }
126 }
127 }
128
129 finishRefresh