摘自官網java
- Create stand-alone Spring applications
- Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
- Provide opinionated 'starter' dependencies to simplify your build configuration
- Automatically configure Spring and 3rd party libraries whenever possible
- Provide production-ready features such as metrics, health checks and externalized configuration
- Absolutely no code generation and no requirement for XML configuration
目前 spring boot 已被普遍使用,關於 spring boot 的文章更是隨處可見。所以,咱們就串聯瑣碎的知識點,簡單整理出一條線。使用spring boot 已經有一段時間了,可是有些知識點仍是比較模糊。它啓動過程都幹了什麼?如何實現自動配置的?啓動 web 應用的時候何時啓動 tomcat 服務的?發起一個 http 請求會經歷什麼過程?react
spring boot 啓動過程的源碼分析網上有不少,並且比較詳細,就再也不詳細贅述了。有興趣的同窗自行翻閱資料哈~web
在 spring boot 啓動的時候,會根據工程的環境(主要是根據特定的類名稱)肯定一個 ConfigurableApplicationContext
的上下文對象,咱們就以 AnnotationConfigServletWebServerApplicationContext
作例子。spring
// 建立ConfigurableApplicationContext,若是是servlet環境會建立AnnotationConfigServletWebServerApplicationContext context = createApplicationContext(); // 從spring.factories中獲取SpringBootExceptionReporter工廠,並初始化spring boot的異常分析對象 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 刷新appContext,這裏開始啓動spring管理bean refreshContext(context); // afterRefresh方法是protected的空實現,咱們能夠用這個鉤子作一些事情 afterRefresh(context, applicationArguments);
重點關注 refreshContext
方法,這個方法強制轉換對象爲 AbstractApplicationContext 後執行他的 refresh
方法瀏覽器
protected void refresh(ApplicationContext applicationContext) { Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); ((AbstractApplicationContext) applicationContext).refresh(); }
常常看 spring 源碼的同窗,看到這一步應該就比較熟悉了,和咱們傳統的 SSM 框架同樣的啓動流程。tomcat
啓動過程當中功能簡述springboot
SpringFactoriesLoader
提供通用的工廠加載機制,具體是解析工程下全部jar包中的 META-INF/spring.factories 文件,並提供反序列化 bean 功能Properties
和 Yaml
配置文件的解析,以及數據綁定SERVLET
、REACTIVE
、NON
, 以建立相應的 ConfigurableApplicationContext
來管理 Bean 的生命週期SPI
接口,包括 PropertySourceLoader
、SpringApplicationRunListener
、SpringBootExceptionReporter
、ApplicationContextInitializer
、ApplicationListener
、EnvironmentPostProcessor
、FailureAnalyzer
、FailureAnalysisReporter
等瞭解了 SpringFactoriesLoader
實現相似 java spi 的功能,咱們就能夠自定義實現 SPI
的接口。實現方式:app
@Component
run
返回的 ConfigurableApplicationContext
中添加(部分接口能夠)接口=實現
的形式存放咱們的 spring boot 的啓動類一般會使用 @SpringBootApplication
,該註解包含了@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
,而 @EnableAutoConfiguration
是實現自動配置的關鍵框架
... @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
在前面咱們提到 spring boot 啓動會執行到AbstractApplicationContext.refresh(),以後調用ConfigurationClassPostProcessor.processConfigBeanDefinitions掃描全部的 @Import
,並執行 AutoConfigurationImportSelector
的 selectImports
,該方法調用 SpringFactoriesLoader
讀取spring.factories獲取 EnableAutoConfiguration
對應的實現類。ide
方法執行棧
refresh --> invokeBeanFactoryPostProcessors --> ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry --> AutoConfigurationImportSelector.selectImports
最後會在 AbstractApplicationContext.finishBeanFactoryInitialization 初始化非懶加載的對象,完成自動化配置。
首先咱們來看下 AnnotationConfigServletWebServerApplicationContext
類關係圖,因爲圖比較大就不放出來了。
AnnotationConfigServletWebServerApplicationContext --> ServletWebServerApplicationContext --> GenericWebApplicationContext --> GenericApplicationContext --> AbstractApplicationContext
因此在執行 AbstractApplicationContext.refresh 中調用 onRefresh
時,會調用 ServletWebServerApplicationContext.onRefresh
再調用 createWebServer
// ServletWebServerApplicationContext.createWebServer private void createWebServer() { WebServer webServer = this.webServer; ServletContext servletContext = getServletContext(); //若是配有配置WebServer,則從BeanFactory中獲取一個ServletWebServerFactory的實例 if (webServer == null && servletContext == null) { ServletWebServerFactory factory = getWebServerFactory(); this.webServer = factory.getWebServer(getSelfInitializer()); } else if (servletContext != null) { try { // 調用selfInitialize,配置servletContext,註冊servletContext到spring context中,並調用ServletContextInitializer的onStartup鉤子方法 getSelfInitializer().onStartup(servletContext); } catch (ServletException ex) { throw new ApplicationContextException("Cannot initialize servlet context", ex); } } // 初始化servletContext配置 initPropertySources(); }
最後,咱們經過一圖簡單解答前言中提到的問題。
當 spring boot 啓動完成後,正常狀況下一次 http 請求大體會經歷這樣一個過程。用戶輸入訪問地址 --> 瀏覽器客戶端發起請求 --> web 服務(tomcat、jetty)轉發請求 --> 請求處理(servlet規範、reactive規範、其餘自定義的) --> 響應結果
注:第一次發博客,不免有所不足,甚至出現錯誤的地方,歡迎你們指正,謝謝。