總在說 Spring Boot 內(nèi)置了 Tomcat 啟動,那它的原理你說的清楚嗎?
閱讀本文大概需要 7 分鐘。
來自:cnblogs.com/sword-successful/p/11383723.html
內(nèi)置tomcat
<dependency>
???<groupId>org.springframework.bootgroupId>
???<artifactId>spring-boot-starter-webartifactId>
???<version>2.1.6.RELEASEversion>
dependency>
@SpringBootApplication
public?class?MySpringbootTomcatStarter{
????public?static?void?main(String[]?args)?{
????????Long?time=System.currentTimeMillis();
????????SpringApplication.run(MySpringbootTomcatStarter.class);
??????? System.out.println("===應用啟動耗時:"+(System.currentTimeMillis()-time)+"===");
????}
}
發(fā)布生產(chǎn)
????org.springframework.boot
????spring-boot-starter-web
????
????
????????
????????????org.springframework.boot
????????????spring-boot-starter-tomcat
????????
????
????javax.servlet
????javax.servlet-api
????3.1.0
????provided
@SpringBootApplication
public?class?MySpringbootTomcatStarter?extends?SpringBootServletInitializer?{
????public?static?void?main(String[]?args)?{
????????Long?time=System.currentTimeMillis();
????????SpringApplication.run(MySpringbootTomcatStarter.class);
????????System.out.println("===應用啟動耗時:"+(System.currentTimeMillis()-time)+"===");
????}
????@Override
????protected?SpringApplicationBuilder?configure(SpringApplicationBuilder?builder)?{
????????return?builder.sources(this.getClass());
????}
}
從main函數(shù)說起
public?static?ConfigurableApplicationContext?run(Class>?primarySource,?String...?args)?{
????return?run(new?Class[]{primarySource},?args);
}
--這里run方法返回的是ConfigurableApplicationContext
public?static?ConfigurableApplicationContext?run(Class>[]?primarySources,?String[]?args)?{
?return?(new?SpringApplication(primarySources)).run(args);
}
public?ConfigurableApplicationContext?run(String...?args)?{
?ConfigurableApplicationContext?context?=?null;
?Collection?exceptionReporters?=?new?ArrayList();
?this.configureHeadlessProperty();
?SpringApplicationRunListeners?listeners?=?this.getRunListeners(args);
?listeners.starting();
?Collection?exceptionReporters;
?try?{
??ApplicationArguments?applicationArguments?=?new?DefaultApplicationArguments(args);
??ConfigurableEnvironment?environment?=?this.prepareEnvironment(listeners,?applicationArguments);
??this.configureIgnoreBeanInfo(environment);
??//打印banner,這里你可以自己涂鴉一下,換成自己項目的logo
??Banner?printedBanner?=?this.printBanner(environment);
??//創(chuàng)建應用上下文
??context?=?this.createApplicationContext();
??exceptionReporters?=?this.getSpringFactoriesInstances(SpringBootExceptionReporter.class,?new?Class[]{ConfigurableApplicationContext.class},?context);
??//預處理上下文
??this.prepareContext(context,?environment,?listeners,?applicationArguments,?printedBanner);
??//刷新上下文
??this.refreshContext(context);
??//再刷新上下文
??this.afterRefresh(context,?applicationArguments);
??listeners.started(context);
??this.callRunners(context,?applicationArguments);
?}?catch?(Throwable?var10)?{
?}
?try?{
??listeners.running(context);
??return?context;
?}?catch?(Throwable?var9)?{
?}
}
創(chuàng)建上下文
//創(chuàng)建上下文
protected?ConfigurableApplicationContext?createApplicationContext()?{
?Class>?contextClass?=?this.applicationContextClass;
?if?(contextClass?==?null)?{
??try?{
???switch(this.webApplicationType)?{
????case?SERVLET:
????????????????????//創(chuàng)建AnnotationConfigServletWebServerApplicationContext
????????contextClass?=?Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
?????break;
????case?REACTIVE:
?????contextClass?=?Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
?????break;
????default:
?????contextClass?=?Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
???}
??}?catch?(ClassNotFoundException?var3)?{
???throw?new?IllegalStateException("Unable?create?a?default?ApplicationContext,?please?specify?an?ApplicationContextClass",?var3);
??}
?}
?return?(ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
刷新上下文
//SpringApplication.java
//刷新上下文
private?void?refreshContext(ConfigurableApplicationContext?context)?{
?this.refresh(context);
?if?(this.registerShutdownHook)?{
??try?{
???context.registerShutdownHook();
??}?catch?(AccessControlException?var3)?{
??}
?}
}
//這里直接調(diào)用最終父類AbstractApplicationContext.refresh()方法
protected?void?refresh(ApplicationContext?applicationContext)?{
?((AbstractApplicationContext)applicationContext).refresh();
}
//AbstractApplicationContext.java
public?void?refresh()?throws?BeansException,?IllegalStateException?{
?synchronized(this.startupShutdownMonitor)?{
??this.prepareRefresh();
??ConfigurableListableBeanFactory?beanFactory?=?this.obtainFreshBeanFactory();
??this.prepareBeanFactory(beanFactory);
??try?{
???this.postProcessBeanFactory(beanFactory);
???this.invokeBeanFactoryPostProcessors(beanFactory);
???this.registerBeanPostProcessors(beanFactory);
???this.initMessageSource();
???this.initApplicationEventMulticaster();
???//調(diào)用各個子類的onRefresh()方法,也就說這里要回到子類:ServletWebServerApplicationContext,調(diào)用該類的onRefresh()方法
???this.onRefresh();
???this.registerListeners();
???this.finishBeanFactoryInitialization(beanFactory);
???this.finishRefresh();
??}?catch?(BeansException?var9)?{
???this.destroyBeans();
???this.cancelRefresh(var9);
???throw?var9;
??}?finally?{
???this.resetCommonCaches();
??}
?}
}
//ServletWebServerApplicationContext.java
//在這個方法里看到了熟悉的面孔,this.createWebServer,神秘的面紗就要揭開了。
protected?void?onRefresh()?{
?super.onRefresh();
?try?{
??this.createWebServer();
?}?catch?(Throwable?var2)?{
?}
}
//ServletWebServerApplicationContext.java
//這里是創(chuàng)建webServer,但是還沒有啟動tomcat,這里是通過ServletWebServerFactory創(chuàng)建,那么接著看下ServletWebServerFactory
private?void?createWebServer()?{
?WebServer?webServer?=?this.webServer;
?ServletContext?servletContext?=?this.getServletContext();
?if?(webServer?==?null?&&?servletContext?==?null)?{
??ServletWebServerFactory?factory?=?this.getWebServerFactory();
??this.webServer?=?factory.getWebServer(new?ServletContextInitializer[]{this.getSelfInitializer()});
?}?else?if?(servletContext?!=?null)?{
??try?{
???this.getSelfInitializer().onStartup(servletContext);
??}?catch?(ServletException?var4)?{
??}
?}
?this.initPropertySources();
}
//接口
public?interface?ServletWebServerFactory?{
????WebServer?getWebServer(ServletContextInitializer...?initializers);
}
//實現(xiàn)
AbstractServletWebServerFactory
JettyServletWebServerFactory
TomcatServletWebServerFactory
UndertowServletWebServerFactory

//TomcatServletWebServerFactory.java
//這里我們使用的tomcat,所以我們查看TomcatServletWebServerFactory。到這里總算是看到了tomcat的蹤跡。
@Override
public?WebServer?getWebServer(ServletContextInitializer...?initializers)?{
?Tomcat?tomcat?=?new?Tomcat();
?File?baseDir?=?(this.baseDirectory?!=?null)???this.baseDirectory?:?createTempDir("tomcat");
?tomcat.setBaseDir(baseDir.getAbsolutePath());
????//創(chuàng)建Connector對象
?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);
}
protected?TomcatWebServer?getTomcatWebServer(Tomcat?tomcat)?{
?return?new?TomcatWebServer(tomcat,?getPort()?>=?0);
}
//Tomcat.java
//返回Engine容器,看到這里,如果熟悉tomcat源碼的話,對engine不會感到陌生。
public?Engine?getEngine()?{
????Service?service?=?getServer().findServices()[0];
????if?(service.getContainer()?!=?null)?{
????????return?service.getContainer();
????}
????Engine?engine?=?new?StandardEngine();
????engine.setName(?"Tomcat"?);
????engine.setDefaultHost(hostname);
????engine.setRealm(createDefaultRealm());
????service.setContainer(engine);
????return?engine;
}
//Engine是最高級別容器,Host是Engine的子容器,Context是Host的子容器,Wrapper是Context的子容器
//TomcatWebServer.java
//這里調(diào)用構造函數(shù)實例化TomcatWebServer
public?TomcatWebServer(Tomcat?tomcat,?boolean?autoStart)?{
?Assert.notNull(tomcat,?"Tomcat?Server?must?not?be?null");
?this.tomcat?=?tomcat;
?this.autoStart?=?autoStart;
?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()))?{
?????removeServiceConnectors();
????}
???});
???//===啟動tomcat服務===
???this.tomcat.start();
???rethrowDeferredStartupExceptions();
???try?{
????ContextBindings.bindClassLoader(context,?context.getNamingToken(),?getClass().getClassLoader());
???}
???catch?(NamingException?ex)?{
???}
????????????//開啟阻塞非守護進程
???startDaemonAwaitThread();
??}
??catch?(Exception?ex)?{
???stopSilently();
???destroySilently();
???throw?new?WebServerException("Unable?to?start?embedded?Tomcat",?ex);
??}
?}
}
//Tomcat.java
public?void?start()?throws?LifecycleException?{
?getServer();
?server.start();
}
//這里server.start又會回到TomcatWebServer的
public?void?stop()?throws?LifecycleException?{
?getServer();
?server.stop();
}
//TomcatWebServer.java
//啟動tomcat服務
@Override
public?void?start()?throws?WebServerException?{
?synchronized?(this.monitor)?{
??if?(this.started)?{
???return;
??}
??try?{
???addPreviouslyRemovedConnectors();
???Connector?connector?=?this.tomcat.getConnector();
???if?(connector?!=?null?&&?this.autoStart)?{
????performDeferredLoadOnStartup();
???}
???checkThatConnectorsHaveStarted();
???this.started?=?true;
???//在控制臺打印這句日志,如果在yml設置了上下文,這里會打印
???logger.info("Tomcat?started?on?port(s):?"?+?getPortsDescription(true)?+?"?with?context?path?'"
?????+?getContextPath()?+?"'");
??}
??catch?(ConnectorStartFailedException?ex)?{
???stopSilently();
???throw?ex;
??}
??catch?(Exception?ex)?{
???throw?new?WebServerException("Unable?to?start?embedded?Tomcat?server",?ex);
??}
??finally?{
???Context?context?=?findContext();
???ContextBindings.unbindClassLoader(context,?context.getNamingToken(),?getClass().getClassLoader());
??}
?}
}
//關閉tomcat服務
@Override
public?void?stop()?throws?WebServerException?{
?synchronized?(this.monitor)?{
??boolean?wasStarted?=?this.started;
??try?{
???this.started?=?false;
???try?{
????stopTomcat();
????this.tomcat.destroy();
???}
???catch?(LifecycleException?ex)?{
???}
??}
??catch?(Exception?ex)?{
???throw?new?WebServerException("Unable?to?stop?embedded?Tomcat",?ex);
??}
??finally?{
???if?(wasStarted)?{
????containerCounter.decrementAndGet();
???}
??}
?}
}
附:tomcat頂層結構圖

Engine>Host>Context>Wrapper容器又是怎么回事呢?我們來看下圖:
總結
推薦閱讀:
SpringBoot+RabbitMQ (保證消息100%投遞成功并被消費)
微信掃描二維碼,關注我的公眾號
朕已閱?

