springboot啟動時,會自動識別出當前環境是否是web環境還是非web環境。
默認的web環境的context(DEFAULT_WEB_CONTEXT_CLASS):org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
默認的非web環境的context(DEFAULT_CONTEXT_CLASS):org.springframework.context.annotation.AnnotationConfigApplicationContext
以下代碼為springboot啟動類springApplication創建context代碼:
/** * Strategy method used to create the {@link ApplicationContext}. By default this * method will respect any explicitly set application context or application context * class before falling back to a suitable default. * @return the application context (not yet refreshed) * @see #setApplicationContextClass(Class) */ protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
那么我們來詳細看下默認的web環境的AnnotationConfigServletWebServerApplicationContext的具體實現:
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext implements AnnotationConfigRegistry
發現AnnotationConfigServletWebServerApplicationContext繼承了org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext,
我們看AnnotationConfigServletWebServerApplicationContext的代碼,發現並沒有和webServer(tomcat,jetty....)相關的代碼。那么我們繼續來看下父類ServletWebServerApplicationContext的實現:
ServletWebServerApplicationContext:發現這個類是boot包下的,繼承了GenericWebApplicationContext是spring-web這個jar包,推斷springboot嵌入webServer的邏輯很有可能是在這個ServletWebServerApplicationContext中
類結構:public class ServletWebServerApplicationContext extends GenericWebApplicationContext implements ConfigurableWebServerApplicationContext
我們終於在org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext看到了和webServer相關的代碼:
@Override protected void onRefresh() { super.onRefresh(); try { createWebServer(); } catch (Throwable ex) { throw new ApplicationContextException("Unable to start web server", ex); } }
@Override protected void finishRefresh() { super.finishRefresh(); WebServer webServer = startWebServer(); if (webServer != null) { publishEvent(new ServletWebServerInitializedEvent(webServer, this)); } }
其中onRefresh方法會在void org.springframework.context.support.AbstractApplicationContext.refresh() 中會在context注冊BeanFactoryPostProcessor、執行BeanFactoryPostProcessor、注冊BeanPostProcessor之后調用,
而finishRefresh方法會在void org.springframework.context.support.AbstractApplicationContext.finishRefresh()中會在context完成各種初始化(初始化bean)后被調用到,從而在context啟動完成后,啟動WebServer(tomcat、jetty)...
接下來我們看下創建WebServer和啟動WebServer的邏輯:
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(); }
private WebServer startWebServer() { WebServer webServer = this.webServer; if (webServer != null) { webServer.start(); } return webServer; }