大家都用过spring boot,都知道他启动的时候内置一个Tomcat,但是他是怎么来的,你们知道吗
这篇博客将带你们走进spring boot的源码,看看spring boot底层是如何加载tomcat的,走起发车!
入口SpringApplication.run()
这个方法大家都很熟悉我就不细讲了,我们从这进去一直找到public ConfigurableApplicationContext run(String... args)
,然后找到refreshContext这个方法
public ConfigurableApplicationContext run(String... args) {
//此处省略
//入口方法
this.refreshContext(context);
//此处省略
}
继续往refresh这个方法找,一直跟着refresh找,直到找到ConfigurableApplicationContext
的抽象类
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh((ApplicationContext)context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
//此处省略
//web容器上下文入口
void refresh() throws BeansException, IllegalStateException;
//此处省略
}
我们找到他的实现类,我们看到有三个对不对,这时候我们选择AbstractApplicationContext
,不要选ServletWebServerApplicationContext
,因为ServletWebServerApplicationContext
是AbstractApplicationContext
的子类,我们先看他的抽象方法
进入到AbstractApplicationContext
中,我们重点看onRefresh
方法
这是Spring 源码中的核心代码,这是一个模板方法,里面有个很多钩子函数,这里我就不省略代码了,因为这段代码很重要,在这里我们可以看到spring 的生命周期。
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();
//加载bean
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
点进去他是一个空实现
protected void onRefresh() throws BeansException {
}
我们 找到他的实现类ServletWebServerApplicationContext
,这是加载web容器的上下文,我们可以明显看到createWebServer
就是一个创建web容器的方法
protected void onRefresh() {
super.onRefresh();
try {
//创建web容器
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
我们进去源码继续看,有个getWebServerFactory
方法,这是获取webserver工厂类的方法,相信我们离真相不远了
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
//获取webServerr工厂
ServletWebServerFactory factory = this.getWebServerFactory();
//通过工厂生成webServer
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
}
this.initPropertySources();
}
我们继续看可以看到其实我们是获取ServletWebServerFactory的bean,那ServletWebServerFactory具体有什么实现呢
protected ServletWebServerFactory getWebServerFactory() {
String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
//此处省略
}
看到这是不是很清晰啦,我们直接找到TomcatServletWebServerFactory
,看他的getWebServer
实现
很清晰的看到,这就是tomcat的配置,host,connector之类的,相信以前我们学tomcat的时候都见过
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
//启动web容器
return this.getTomcatWebServer(tomcat);
}
tomcat是在上文中的getTomcatWebServer
中启动的,我们再深入进去
protected TomcatWebServer getTomcatWebServer(Tomcat tomcat) {
return new TomcatWebServer(tomcat, this.getPort() >= 0, this.getShutdown());
}
这是一个TomcatWebServer的构造方法,我们再点进去
public TomcatWebServer(Tomcat tomcat, boolean autoStart, Shutdown shutdown) {
//此处省略
//初始化tomcat
this.initialize();
}
进入initialize
方法,不用说大家都知道tomcat.start
就是启动tomcat啦
private void initialize() throws WebServerException {
logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
synchronized(this.monitor) {
try {
this.addInstanceIdToEngineName();
Context context = this.findContext();
context.addLifecycleListener((event) -> {
if (context.equals(event.getSource()) && "start".equals(event.getType())) {
this.removeServiceConnectors();
}
});
// 启动tomcat
this.tomcat.start();
this.rethrowDeferredStartupExceptions();
try {
ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
} catch (NamingException var5) {
}
this.startDaemonAwaitThread();
} catch (Exception var6) {
this.stopSilently();
this.destroySilently();
throw new WebServerException("Unable to start embedded Tomcat", var6);
}
}
}
这篇文章下来,是不是感觉以前不理解的东西一下子就清晰了呢,这篇文章希望能帮助大家能更简单的去了解源码,学习总是快乐的嘿嘿