我们肯定对SpringBoot默认内部集成了Tomcat web环境不陌生,虽然reactive容器逐渐崭露头角,但相信大部分的用户还是使用了Tomcat的容器的。不知道是否有同学和我一样,对SpringBoot如何集成了tomcat有好奇,这里我们从springboot的源码中查看一下,它是如何集成tomcat的;
先来看springboot的标准启动的代码:
SpringApplication.run(SpringBootApplication.class, args);
1. 首先,同名run方法中:
- public static ConfigurableApplicationContext run(Class>[] primarySources, String[] args) {
- return new SpringApplication(primarySources).run(args);
- }
可以找到创建了SpringApplication对象的代码,从构造方法我们可以找到一个关键点:
this.webApplicationType = WebApplicationType.deduceFromClasspath();
deduceFromClasspath方法会从环境里是否有特定的类来判断WebApplicationType,由于我们没有配置reactive,因此此处会返回WebApplicationType.SERVLET
2. 分析完构造方法之后,我们来看一下run方法的内部,其中有一行:
context = createApplicationContext();
这个方法就会根据上一步的WebApplicationType来决定上下文;在这里我们会执行到
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
3. webServer的创建入口
webServer的创建是在run方法的refreshContext中的。
经过几个跳转我们来到了十分熟悉的,十分出名的 AbstractApplicationContext # refresh方法,重点关注它的onRefresh
- @Override
- protected void onRefresh() {
- super.onRefresh();
- try {
- createWebServer();
- }
- catch (Throwable ex) {
- throw new ApplicationContextException("Unable to start web server", ex);
- }
- }
其中有一个createWebServer方法
- private void createWebServer() {
- WebServer webServer = this.webServer;
- ServletContext servletContext = getServletContext();
- if (webServer == null && servletContext == null) {
- ServletWebServerFactory factory = getWebServerFactory();
- this.webServer = factory.getWebServer(getSelfInitializer());
- }
- else if (servletContext != null) {
- try {
- getSelfInitializer().onStartup(servletContext);
- }
- catch (ServletException ex) {
- throw new ApplicationContextException("Cannot initialize servlet context", ex);
- }
- }
- initPropertySources();
- }
这个方法先会创建一个webServer工厂类,默认情况下,就是TomcatServletWebServerFactory了!
我们看下它的getWebServer方法:
- @Override
- public WebServer getWebServer(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 getTomcatWebServer(tomcat);
- }
哈哈,成功找到了。
createWebServer接下来会设置webServer属性,最后调用initPropertySources方法(如果环境中存在servletContextInitParams/servletConfigInitParams属性,会对其进行一个替换),并不是关注的重点,我们先跳过;
4. 我们跟踪到AbstractApplicationContext # refresh -> finishRefresh方法:
- @Override
- protected void finishRefresh() {
- super.finishRefresh();
- WebServer webServer = startWebServer();
- if (webServer != null) {
- publishEvent(new ServletWebServerInitializedEvent(webServer, this));
- }
- }
这里会启动WebServer
- private WebServer startWebServer() {
- WebServer webServer = this.webServer;
- if (webServer != null) {
- webServer.start();
- }
- return webServer;
- }
在默认情况下,我们就会调用到TomcatWebServer方法了;