springBoot深入理解--啟動原理
Spring Boot是為了簡化Spring應用的建立、執行、除錯、部署等而出現的,使用它可以做到專注於Spring應用的開發,而無需過多關注XML的配置。
簡單來說,它提供了一堆依賴打包,並已經按照使用習慣解決了依賴問題---習慣大於約定。
注:Spring Boot預設使用tomcat作為伺服器,使用logback提供日誌記錄。
一:使用前提
Spring Boot提供了一系列的依賴包,所以需要構建工具的支援:maven 或 gradle。個人僅熟悉maven,所以下面的內容都是maven相關的。
使用
① 新建一個maven專案。
② pom中parent設為 spring-boot-starter-parent
③ 新增應用需要的starter模組,作為示例,我們僅新增web starter模組。
這裡需要解釋下starter模組,簡單的說,就是一系列的依賴包組合。例如web starter模組,就是包含了Spring Boot預定義的一些Web開發的常用依賴:(其中starter模組 Spring Boot應用啟動器基本的一共有44種附文末)
○ spring-web, spring-webmvc Spring WebMvc框架
○ tomcat-embed-* 內嵌Tomcat容器
○ jackson 處理json資料
○ spring-* Spring框架
○ spring-boot-autoconfigure Spring Boot提供的自動配置功能
換句話說,當你添加了相應的starter模組,就相當於添加了相應的所有必須的依賴包。
至此,pom內容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>cn.larry.spring</groupId> <artifactId>larry-spring-demo4</artifactId> <version>0.0.1-SNAPSHOT</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.0.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> </project> 基本上,如果沒有特別的需要,現在就可以直接寫Controller了!!!--特別的需要 是指設定容器、訪問埠、路徑等。後面再解釋。
package cn.larry.spring.controller; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @EnableAutoConfiguration public class SampleController { @RequestMapping("/") @ResponseBody String home() { return "Hello World!"; } public static void main(String[] args) throws Exception { SpringApplication.run(SampleController.class, args); } }
這裡有兩個新東西:@EnableAutoConfiguration 和 SpringApplication 。
二:配置引數詳解
SpringBootApplication背後的祕密
雖然定義使用了多個Annotation進行了原資訊標註,但實際上重要的只有三個Annotation:
-
@Configuration(@SpringBootConfiguration點開檢視發現裡面還是應用了@Configuration)
-
@EnableAutoConfiguration
-
@ComponentScan
所以,如果我們使用如下的SpringBoot啟動類,整個SpringBoot應用依然可以與之前的啟動類功能對等:
每次寫這3個比較累,所以寫一個@SpringBootApplication方便點。接下來分別介紹這3個Annotation。
@Configuration
這裡的@Configuration對我們來說不陌生,它就是JavaConfig形式的Spring Ioc容器的配置類使用的那個@Configuration,SpringBoot社群推薦使用基於JavaConfig的配置形式,所以,這裡的啟動類標註了@Configuration之後,本身其實也是一個IoC容器的配置類。
舉幾個簡單例子回顧下,XML跟config配置方式的區別:
-
表達形式層面
基於XML配置的方式是這樣:
而基於JavaConfig的配置方式是這樣:
任何一個標註了@Configuration的Java類定義都是一個JavaConfig配置類。
-
註冊bean定義層面
基於XML的配置形式是這樣:
而基於JavaConfig的配置形式是這樣的:
任何一個標註了@Bean的方法,其返回值將作為一個bean定義註冊到Spring的IoC容器,方法名將預設成該bean定義的id。
-
表達依賴注入關係層面
為了表達bean與bean之間的依賴關係,在XML形式中一般是這樣:
而基於JavaConfig的配置形式是這樣的:
如果一個bean的定義依賴其他bean,則直接呼叫對應的JavaConfig類中依賴bean的建立方法就可以了。
@ComponentScan
@ComponentScan這個註解在Spring中很重要,它對應XML配置中的元素,@ComponentScan的功能其實就是自動掃描並載入符合條件的元件(比如@Component和@Repository等)或者bean定義,最終將這些bean定義載入到IoC容器中。
我們可以通過basePackages等屬性來細粒度的定製@ComponentScan自動掃描的範圍,如果不指定,則預設Spring框架實現會從宣告@ComponentScan所在類的package進行掃描。
注:所以SpringBoot的啟動類最好是放在root package下,因為預設不指定basePackages。
@EnableAutoConfiguration
個人感覺@EnableAutoConfiguration這個Annotation最為重要,所以放在最後來解讀,大家是否還記得Spring框架提供的各種名字為@Enable開頭的Annotation定義?比如@EnableScheduling、@EnableCaching、@EnableMBeanExport等,@EnableAutoConfiguration的理念和做事方式其實一脈相承,簡單概括一下就是,藉助@Import的支援,收集和註冊特定場景相關的bean定義。
-
@EnableScheduling是通過@Import將Spring排程框架相關的bean定義都載入到IoC容器。
-
@EnableMBeanExport是通過@Import將JMX相關的bean定義載入到IoC容器。
而@EnableAutoConfiguration也是藉助@Import的幫助,將所有符合自動配置條件的bean定義載入到IoC容器,僅此而已!
@EnableAutoConfiguration作為一個複合Annotation,其自身定義關鍵資訊如下:
其中,最關鍵的要屬@Import(EnableAutoConfigurationImportSelector.class),藉助EnableAutoConfigurationImportSelector,@EnableAutoConfiguration可以幫助SpringBoot應用將所有符合條件的@Configuration配置都載入到當前SpringBoot建立並使用的IoC容器。就像一隻“八爪魚”一樣
藉助於Spring框架原有的一個工具類:SpringFactoriesLoader的支援,@EnableAutoConfiguration可以智慧的自動配置功效才得以大功告成!
自動配置幕後英雄:SpringFactoriesLoader詳解
SpringFactoriesLoader屬於Spring框架私有的一種擴充套件方案,其主要功能就是從指定的配置檔案META-INF/spring.factories載入配置。
配合@EnableAutoConfiguration使用的話,它更多是提供一種配置查詢的功能支援,即根據@EnableAutoConfiguration的完整類名org.springframework.boot.autoconfigure.EnableAutoConfiguration作為查詢的Key,獲取對應的一組@Configuration類
上圖就是從SpringBoot的autoconfigure依賴包中的META-INF/spring.factories配置檔案中摘錄的一段內容,可以很好地說明問題。
所以,@EnableAutoConfiguration自動配置的魔法騎士就變成了:從classpath中搜尋所有的META-INF/spring.factories配置檔案,並將其中org.springframework.boot.autoconfigure.EnableutoConfiguration對應的配置項通過反射(Java Refletion)例項化為對應的標註了@Configuration的JavaConfig形式的IoC容器配置類,然後彙總為一個並載入到IoC容器。
深入探索SpringApplication執行流程
SpringApplication的run方法的實現是我們本次旅程的主要線路,該方法的主要流程大體可以歸納如下:
1) 如果我們使用的是SpringApplication的靜態run方法,那麼,這個方法裡面首先要建立一個SpringApplication物件例項,然後呼叫這個建立好的SpringApplication的例項方法。在SpringApplication例項初始化的時候,它會提前做幾件事情:
-
根據classpath裡面是否存在某個特徵類(org.springframework.web.context.ConfigurableWebApplicationContext)來決定是否應該建立一個為Web應用使用的ApplicationContext型別。
-
使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationContextInitializer。
-
使用SpringFactoriesLoader在應用的classpath中查詢並載入所有可用的ApplicationListener。
-
推斷並設定main方法的定義類。
2) SpringApplication例項初始化完成並且完成設定後,就開始執行run方法的邏輯了,方法執行伊始,首先遍歷執行所有通過SpringFactoriesLoader可以查詢到並載入的SpringApplicationRunListener。呼叫它們的started()方法,告訴這些SpringApplicationRunListener,“嘿,SpringBoot應用要開始執行咯!”。
3) 建立並配置當前Spring Boot應用將要使用的Environment(包括配置要使用的PropertySource以及Profile)。
4) 遍歷呼叫所有SpringApplicationRunListener的environmentPrepared()的方法,告訴他們:“當前SpringBoot應用使用的Environment準備好了咯!”。
5) 如果SpringApplication的showBanner屬性被設定為true,則列印banner。
6) 根據使用者是否明確設定了applicationContextClass型別以及初始化階段的推斷結果,決定該為當前SpringBoot應用建立什麼型別的ApplicationContext並建立完成,然後根據條件決定是否新增ShutdownHook,決定是否使用自定義的BeanNameGenerator,決定是否使用自定義的ResourceLoader,當然,最重要的,將之前準備好的Environment設定給建立好的ApplicationContext使用。
7) ApplicationContext建立好之後,SpringApplication會再次藉助Spring-FactoriesLoader,查詢並載入classpath中所有可用的ApplicationContext-Initializer,然後遍歷呼叫這些ApplicationContextInitializer的initialize(applicationContext)方法來對已經建立好的ApplicationContext進行進一步的處理。
8) 遍歷呼叫所有SpringApplicationRunListener的contextPrepared()方法。
9) 最核心的一步,將之前通過@EnableAutoConfiguration獲取的所有配置以及其他形式的IoC容器配置載入到已經準備完畢的ApplicationContext。
10) 遍歷呼叫所有SpringApplicationRunListener的contextLoaded()方法。
11) 呼叫ApplicationContext的refresh()方法,完成IoC容器可用的最後一道工序。
12) 查詢當前ApplicationContext中是否註冊有CommandLineRunner,如果有,則遍歷執行它們。
13) 正常情況下,遍歷執行SpringApplicationRunListener的finished()方法、(如果整個過程出現異常,則依然呼叫所有SpringApplicationRunListener的finished()方法,只不過這種情況下會將異常資訊一併傳入處理)
去除事件通知點後,整個流程如下:
SpringApplication 則是用於從main方法啟動Spring應用的類。預設,它會執行以下步驟:
- 建立一個合適的ApplicationContext例項 (取決於classpath)。
- 註冊一個CommandLinePropertySource,以便將命令列引數作為Spring properties。
- 重新整理application context,載入所有單例beans。
- 啟用所有CommandLineRunner beans。
預設,直接使用SpringApplication 的靜態方法run()即可。但也可以建立例項,並自行配置需要的設定。
總結
到此,SpringBoot的核心元件完成了基本的解析,綜合來看,大部分都是Spring框架背後的一些概念和實踐方式,SpringBoot只是在這些概念和實踐上對特定的場景事先進行了固化和昇華,而也恰恰是這些固化讓我們開發基於Sping框架的應用更加方便高效。
下面對啟動的提示每一行做一解釋:
⑥ 根據這個資訊,我們可以看出很多東西,不過現在先訪問一下吧。
若想要路徑中加入專案名稱,將專案路徑直接設為根路徑 server.contextPath=/aaa
啟動時的資訊:
第 9 行,啟動SampleController。 第10行,查詢active profile,無,設為default。 第11行,重新整理上下文。 第12行,初始化tomcat,設定埠8080,設定訪問方式為http。 第13行,啟動tomcat服務。 第14行,啟動Servlet引擎。 第15行,Spring內嵌的WebApplicationContext 初始化開始。 第16行,Spring內嵌的WebApplicationContext 初始化完成。 第17行,對映servlet,將 dispatcherServlet 對映到 [/] 。 第18行,對映filter,將 characterEncodingFilter 對映到 [/*] 。 第19行,對映filter,將 hiddenHttpMethodFilter 對映到 [/*] 。 第20行,對映filter,將 httpPutFormContentFilter 對映到 [/*] 。 第21行,對映filter,將 requestContextFilter 對映到 [/*] 。 第22行,查詢 @ControllerAdvice。 第23行,對映路徑 "{[/]}" 到 cn.larry.spring.controller.SampleController.home()。 第24行,對映路徑 "{[/error]}" 到 org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)。 第25行,對映路徑 "{[/error],produces=[text/html]}" 到 org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)。 第26行,略。 第27行,略。 第28行,略。 第29行,略。 第30行,tomcat啟動完畢。 第31行,SampleController啟動耗費的時間。 第32行,初始化 dispatcherServlet 。 第33行,dispatcherServlet 的初始化已啟動。 第34行,dispatcherServlet 的初始化已完成。 第35行,收到shutdown關閉請求。 第36行,關閉AnnotationConfigEmbeddedWebApplicationContext。 第37行,略。
從上面的啟動資訊中可以明顯看到SpringMVC的載入過程,特別需要注意的是這種預設方式下載入的幾個 filter 。
具體可以見本文末尾最後三個連結。
參考:
相關推薦
springBoot深入理解--啟動原理
Spring Boot是為了簡化Spring應用的建立、執行、除錯、部署等而出現的,使用它可以做到專注於Spring應用的開發,而無需過多關注XML的配置。 簡單來說,它提供了一堆依賴打包,並已經按照使用習慣解決了依賴問題---習慣大於約定。 注:
深入理解mysqldump原理 --single-transaction --lock-all-tables --master-data
在mysqldump過程中,之前其實一直不是很理解為什麼加了--single-transaction就能保證innodb的資料是完全一致的,而myisam引擎無法保證,必須加--lock-all-tables,前段時間抽空詳細地查看了整個mysqldump過程。 理解master-data和--
記憶體系列二:深入理解硬體原理
本篇文章承接上文繼續介紹DDR記憶體的硬體原理,包括如何定址,時序和時延以及可以為提高記憶體的效能可以有哪些方法。 上次雖然解決了小張的問題,卻引發了他對記憶體原理的興趣。這不他又來找我了,說我還欠他一個解釋。這次我們約在一個咖啡館見面,這次內容有點深入,我帶了些圖片,小張也點了一大杯美式,計劃大幹一
《深入理解mybatis原理》 MyBatis快取機制的設計與實現
本文主要講解MyBatis非常棒的快取機制的設計原理,給讀者們介紹一下MyBatis的快取機制的輪廓,然後會分別針對快取機制中的方方面面展開討論。 MyBatis將資料快取設計成兩級結構,分為一級快取、二級快取: &nb
《深入理解mybatis原理》 MyBatis的二級快取的設計原理
MyBatis的二級快取是Application級別的快取,它可以提高對資料庫查詢的效率,以提高應用的效能。本文將全面分析MyBatis的二級快取的設計原理。 1.MyBatis的快取機制整體設計以及二級快取的工作模式
深入理解計算機原理——程式與執行(二)
浮點數 (1) 浮點數的表示方法; (2) 浮點數的精度與範圍; (3) 浮點數的分佈; (4) 浮點數階碼的表示方法; (5) 浮點數位數規格化; (6) 結合例子學習浮點數的表示方法; (7) IEEE 754標準; 2
簡述JAVA GC回收機制,深入理解GC原理
什麼是“GC” 垃圾回收機制。 為什麼要用“GC” 眾所周知,JAVA 這語言,與C語言不同,Java記憶體(堆記憶體)的分配與回收由JVM垃圾收集器自動完成,比如 C語言自己定義的變數,不用時需要 自己回收這個變數 。JAVA 這就是自動完成了,自動檢測,無用的
深入理解PHP原理之Opcodes
最近要給Yahoo的同事們做一個關於PHP和Apache處理請求的內部機制的講座,剛好寫了些關於Opcodes的文字,就發上來了,這個文章基於 Sara Golemon大師的《Understanding OPcode》 Opcode是一種PHP指令碼編譯後的中間語言,就像Java的Byt
深入理解Memcached原理
1.為什麼要使用memcache 由於網站的高併發讀寫需求,傳統的關係型資料庫開始出現瓶頸,例如: 1)對資料庫的高併發讀寫: 關係型資料庫本身就是個龐然大物,處理過程非常耗時(如解析SQL語句,事務處理等)。如果對關係型資料庫進行高併發讀寫(每秒上萬次的訪問),那麼它是
《深入理解mybatis原理(三)》 MyBatis的一級快取實現詳解 及使用注意事項
0.寫在前面 MyBatis是一個簡單,小巧但功能非常強大的ORM開源框架,它的功能強大也體現在它的快取機制上。MyBatis提供了一級快取、二級快取 這兩個快取機制,能夠很好地處理和維護快取,以提高系統的效能。本文的目的則是向讀者詳細介紹MyBatis的一級快取,深入原始碼,解析MyBa
深入理解PHP原理之函式(Introspecting PHP Function)
宣告:此內容轉載鳥哥,只是留作個人學習、記錄用。為表尊重,特此說明。 在PHP中,函式分為倆種, •一種是zend_internal_function, 這種函式是由擴充套件或者Zend/PHP核心提供的,用’C/C++’編寫的,可以直接執行的函式。 •另外一種是ze
深入理解作業系統原理之檔案系統
一、概述 作業系統對系統的軟體資源(不論是應用軟體和系統軟體)的管理都以檔案方式進行,承擔這部分功能的作業系統稱為檔案系統。 1、檔案 計算機系統對系統中軟體資源:無論是程式或資料、系統軟體或應用軟體都以檔案方式來管理。檔案是存貯在某種介質上的(如磁碟
SpringBoot學習筆記一之【Idea下建立springboot示例、啟動原理分析與兩種部署啟動方式】
1、使用背景 首先說下我們為什麼使用springboot,原因有以下幾點 1、快速建立獨立執行的spring專案以及與主流框架繼承 2、使用嵌入式的Servlet容器,無需打成war包 3、starters自動依賴於版本控制 4、大量的自動配置,簡化開發,也可修改預設值 5、
《深入理解mybatis原理》 Mybatis初始化機制詳解 侵立刪
對於任何框架而言,在使用前都要進行一系列的初始化,MyBatis也不例外。本章將通過以下幾點詳細介紹MyBatis的初始化過程。 1.MyBatis的初始化做了什麼 2. MyBatis基於XML配置檔案建立Configuration物件的過程 &nb
深入理解作業系統原理之程序管理(一)
一、概述 1、為什麼引入程序 程式併發執行時具有如下特徵: 間斷性 程式在併發執行時,由於它們共享資源或為完成同一項任務而相互合作,使在併發程式之間形成了相互制約的關係。相互制約將導致併發程式具有“執行-暫停-執行”這種間斷性活動規律。 失去封閉性
深入理解PHP原理之變數 【轉自(風雪之隅)】
PHP作為一個弱型別,動態的指令碼語言(不嚴格驗證變數型別)。宣告一個變數的時候,並不需要顯示指定它儲存的資料型別。<?php$var = 1; //int$var = "goith"; //st
使用WireShark深入理解HTTPS原理
前端開發,移動開發,後臺開發,都應該知道HTTP通訊,而且現在一些大廠都已經使用HTTPS進行通訊,那HTTPS到底是什麼呢,有什麼好處呢? 一.為什麼要使用HTTPS http是一種通訊上極為簡便的協議,他本身不帶有安全功能,http包在網路上傳輸的過程中難免會被人
深入理解Memcache原理
1.為什麼要使用memcache 由於網站的高併發讀寫需求,傳統的關係型資料庫開始出現瓶頸,例如: 1)對資料庫的高併發讀寫: 關係型資料庫本身就是個龐然大物,處理過程非常耗時(如解析SQL語句,事務處理等)。如果對關係型資料庫進行高併發讀寫(每秒上萬次的訪問),那麼它是
深入理解PHP原理之--echo的實現
PHP原始碼分析-echo實現詳解 原諒出處:http://jackywdx.cn/2009/01/implement_of_php_echo echo,這個是PHP運用得最多的標記之一,算不上是函式,PHP手冊裡這麼寫的,因為它沒有返回值。今天好奇就去看看PHP的原始碼
《深入理解mybatis原理(十二)》 mybatis深入理解之#與$區別
一、介紹 mybatis 中使用 Mapper.xml裡面的配置進行 sql 查詢,經常需要動態傳遞引數,例如我們需要根據使用者的姓名來篩選使用者時,sql 如下: select * from user where name = "Jack";上述 sql 中,我們希