tomcat初始化
startup.bat
catalina.bat获得基础环境变量
调用bin\bootstrap.jar 中的 main 方法,创建了一个Bootstrap类
1.2 调用其init()方法,初始化org.apache.catalina.startup.Catalina类为catalinaDaemon
1.3 然后调用load(args)方法,调用Catalina的load方法Catalina类调用load,解析server.xml文件,创建server实例,调用其init方法
StandardServer类的initInternal方法,遍历调用其中service的init方法
StandardService类的initInternal方法,初始engine容器、executor线程池和connectors连接器
Bootstrap类调用start方法,反射调用Catalina中的start方法
Catalina中的start方法,调用Server的start方法,添加jvm钩子函数确保退出时Catalina终止
StandardServer的startInternal方法,遍历调用其中service的start方法
StandardService类的startInternal方法,启动engine容器、executor线程池和connectors连接器(根据版本启动Socket的accept方法等待连接)
启动StandardEngine容器,调用其startInternal方法,最终调用ContainerBase的startInternal方法,Future模式启动子容器(如Host、Context等,Host、Context初始化也在此时完成),其中Context初始化通过ContextConfig监听器处理。
StandardContext调用startInternal,会依次处理ServletContainerInitializer、Listener处理、Filter处理、加载loadOnStartup的servlet
tomcat请求过程
···忽略Socket处理请求过程,从连接器到容器开始分析
- 调用CoyoteAdapter的service方法来封装request和response,解析uri中参数,获得Host、Context等,使用Container的第一个Pipeline管道,调用其invoke方法
- vavel调用 StandardEngineValve->StandardHostValve->StandardContextValve->StandardWrapperValve
2.1 StandardContext中存在Map<String, String> servletMappings来处理请求的uri,找到对应的StandardWrapper名称
2.2 StandardWrapper中存在ArrayList mappings表明当前servlet支持的uri- 在StandardWrapperValve中完成对过滤器链的执行和servlet的调用
3.1 首先会创建一个servlet实例来处理当前请求 wrapper.allocate();
3.2 为当前请求创建过滤器链 ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
3.3 doFilter执行所有过滤操作,之后调用其默认servlet执行service方法
tomcat在Spring Boot中启动流程
- Spring Boot自动启动tomcat依靠ServletWebServerFactoryAutoConfiguration自动配置类
当存在ServletRequest类且WebApplication类型为SERVLET时才注册,加载注册顺序最高
注册了ServletWeb自定义服务工厂和tomcat自定义Web服务工厂
注册WebServerFactoryCustomizerBeanPostProcessor类如果为WebServerFactory类型则执行customize方法
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@ConditionalOnClass(ServletRequest.class)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,
ServletWebServerFactoryConfiguration.EmbeddedJetty.class,
ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {
@Bean
public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) {
return new ServletWebServerFactoryCustomizer(serverProperties);
}
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
}
- Spring Boot启动过程中ServletWebServerApplicationContext的onRefresh()方法
注册bean,从serverProperties中获得值来初始化webServer工厂参数
忽略的用于.tld 文件扫描的JAR的模式
是否应通过将/附加到路径来重定向对上下文根的请求,默认为true
调用sendRedirect生成的HTTP1.1和更高版本的位置标头将使用相对重定向还是绝对重定向, 默认false相对重定向
是否应启用Tomcat的MBean注册表,默认不启用
tomcat启动
protected void onRefresh() {
// TomcatServletWebServerFactory注册初始化
super.onRefresh();
try {
// 创建web服务器
createWebServer();
}
catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
- createWebServer创建web服务器
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
// 从IOC容器中获得ServletWebServerFactory
ServletWebServerFactory factory = getWebServerFactory();
// 获得WebServer
this.webServer = factory.getWebServer(getSelfInitializer());
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();
}
- getWebServer从工厂中获得Web服务器
创建tomcat,临时文件存放路径
依次创建server、service、connector、engine、host、context和wrapper
tomcat.start启动服务器
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
// 临时文件存放路径
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 根据当前协议创建连接器
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
// 创建StandardServer、StandardService并将连接器传入service中
tomcat.getService().addConnector(connector);
// 定制连接器的一些参数(如port)
customizeConnector(connector);
// 确保连接器被传入service中
tomcat.setConnector(connector);
// 创建StandardEngine加入service中,创建StandardHost放入Engine的child中,且自动部署标识为false
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
// 为service添加附加连接器
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
// 创建TomcatEmbeddedContext,为其添加StandardWrapper子容器(默认名称为default)
prepareContext(tomcat.getHost(), initializers);
// 启动tomcat
return getTomcatWebServer(tomcat);
}
- TomcatWebServer中initialize方法启动tomcat,调用server的start方法