小Hub領(lǐng)讀:我覺得這是SpringBoot的比較核心的功能了,就是這個(gè)starter,自動(dòng)裝配,讓我們可以快速集成第三方框架,真是個(gè)好設(shè)計(jì)!
什么是 Spring BootSpring Boot 基本上是 Spring 框架的擴(kuò)展,它消除了設(shè)置 Spring 應(yīng)用程序所需的復(fù)雜例行配置。我們?cè)谑褂?Spring 框架的時(shí)候,我們接觸得比較多的應(yīng)該是 Spring MVC、 IOC 、 DI 、AOP 等等,而這些框架在使用的過程中會(huì)需要配置大量的 XML,或者需要做很多繁瑣的配置。Spring Boot 可以幫助我們快速搭建一個(gè)基于 Spirng 框架以及 Spring 生態(tài)體系的應(yīng)用解決方案。 我們對(duì)著官網(wǎng)來翻譯一下:
看了上面這么多主要有兩點(diǎn),約定大于配置 和 自動(dòng)裝配。 約定大于配置約定優(yōu)于配置的體現(xiàn)主要是
自動(dòng)裝配講自動(dòng)裝配首先從注解開始,我們從 @SpringBootApplication 點(diǎn)進(jìn)去 可以看到它實(shí)際上是一個(gè)復(fù)合注解,上面四個(gè)是元注解,下面三個(gè)才是重點(diǎn)
我們可以直接用這三個(gè)注解也可以啟動(dòng) Spring Boot 應(yīng)用,只是每次配置三個(gè)注解比較繁瑣,所以直接用一個(gè)復(fù)合注解更方便些。下面是官網(wǎng)的截圖,剛興趣的小伙伴可自行翻譯。 @Configuration@Configuration 這個(gè)注解大家應(yīng)該都用過,它是 JavaConfig 形式的基于 Spring IOC 容器的配置類使用的一種注解。所以在啟動(dòng)類里面標(biāo)注了 @Configuration,意味著它其實(shí)也是一個(gè) IoC 容器的配置類。 傳統(tǒng)意義上的 Spring 應(yīng)用都是基于 xml 形式來配置 bean 的依賴關(guān)系。但是從 Spring3 開始,Spring 就支持了兩種 bean 的配置方式,一種是基于 xml 文件方式,另一種就是 JavaConfig,任何一個(gè)標(biāo)注了 @Configuration 的 Java 類定義都是一個(gè) JavaConfig 配置類。而在這個(gè)配置類中,任何標(biāo)注了 @Bean 的方法,它的返回值都會(huì)作為 Bean 定義注冊(cè)到 Spring 的 IoC 容器,方法名默認(rèn)成為這個(gè) Bean 的 id。然后通過 spring 容器在啟動(dòng)的時(shí)候,把 Bean 進(jìn)行初始化并且,如果 Bean 之間存在依賴關(guān)系,則分析這些已經(jīng)在 IoC 容器中的 Bean 根據(jù)依賴關(guān)系進(jìn)行組裝。 @ComponentScan@ComponentScan 這個(gè)注解大家也用過,這個(gè)很簡(jiǎn)單,就是掃包,相當(dāng)于 xml 配置文件中的 標(biāo)識(shí)需要裝配的類的形式主要是:@Component、@Repository、@Service、@Controller 這類的注解標(biāo)識(shí)的類。(注:@Repository、@Service、@Controller 的底層還是 @Component)。ComponentScan 默認(rèn)會(huì)掃描當(dāng)前 package 下的的所有加了相關(guān)注解標(biāo)識(shí)的類到 IoC 容器中。 @EnableAutoConfiguration好,主角登場(chǎng)了,@EnableAutoConfiguration 是 Spring Boot 的靈魂,是重中之重。從 Spring3.1 開始,提供了一系列的 @Enable 開頭的注解,它是在 JavaConfig 框架上更進(jìn)一步的完善,使用戶在使用 Spring 相關(guān)的框架避免配置大量的代碼從而降低使用的難度。 分享一套SpringBoot開發(fā)博客系統(tǒng)源碼,以及完整開發(fā)文檔!速度保存! 比如常見的一些 Enable 注解:@EnableWebMvc、@EnableScheduling、@EnableAsync 等等。每一個(gè)涉及到 Enable 開頭的注解,都會(huì)帶有一個(gè) @Import 的注解, @EnableAutoConfiguration 也不例外,我們點(diǎn)進(jìn)去發(fā)現(xiàn)如紅框所示。 @Import 注解是什么意思呢?它對(duì)應(yīng) XML 形式下的 <import resource/>,就是導(dǎo)入資源,把多個(gè)分布在不同容器下的配置合并在一個(gè)配置中。@Import 注解可以配置三種不同的 class :
這里導(dǎo)入的是第二種 importSelector,這是一種動(dòng)態(tài)注入 Bean 的技術(shù),我們把 AutoConfigurationImportSelector 點(diǎn)進(jìn)去,發(fā)現(xiàn)它實(shí)現(xiàn)了 ImportSelector 接口。 找到實(shí)現(xiàn)方法 selectImports ,該方法的作用就是找到相應(yīng)的 Bean 注入到容器中。 @Override 再?gòu)?getAutoConfigurationEntry 方法點(diǎn)進(jìn)去,這里面做了許多事情,就是把找到的 Bean 進(jìn)行排除、過濾、去重,我們可以看到 removeDuplicates、remove、filter 等方法。 那具體這些 Bean 從哪里找呢,我們將 getCandidateConfigurations 方法點(diǎn)進(jìn)去,發(fā)現(xiàn)了一個(gè)驚天秘密,那就是在這有一個(gè) META-INF/spring.factories 文件。 當(dāng)然這是一個(gè)報(bào)錯(cuò)信息,我們不敢斷定就是這里,沒關(guān)系,我們把 SpringFactoriesLoader.loadFactoryNames 點(diǎn)進(jìn)去,發(fā)現(xiàn)這里有個(gè)變量 FACTORIES_RESOURCE_LOCATION。 而這個(gè)變量的值還是 META-INF/spring.factories。 看到這里我們很激動(dòng),于是我毫不猶豫的在項(xiàng)目中搜索這個(gè)文件,原來 SpringFactoriesLoader 的作用就是從 classpath/META-INF/spring.factories 文件中,根據(jù) key 來加載對(duì)應(yīng)的類到 Spring IoC 容器中。 看到這里小伙伴就明白了,就是把這么多 Configuration 下的 Bean 加載到容器里嘛, 但是 But ,怎么還有 RabbitMQ、Elasticsearch 這些我都用不到,怎么也給加到容器里來了,那多浪費(fèi)空間和內(nèi)存???小伙伴莫慌,于是我又帶著好奇心理打開了 RabbitMQ 的配置類。 看到這里終于舒了口氣,小伙們有沒有發(fā)現(xiàn)這里多了一些 Conditional 的注解,其實(shí)這些就是條件注解,Spring Boot 也不傻,它會(huì)發(fā)現(xiàn)如果當(dāng)前的 classpath 環(huán)境下沒有相關(guān)聯(lián)的依賴,則意味著這些類沒必要進(jìn)行加載。所以,通過這種條件過濾可以有效的減少 @configuration 類的數(shù)量從而降低 Spring Boot 的啟動(dòng)時(shí)間。
好,有了上面這么多預(yù)備知識(shí)后,就可以開始手寫一個(gè)我們自己的 starter 了。 手寫 starterstarter 工程的命名starter 是一個(gè)開箱即用的組件,減少不必要的重復(fù)代碼,重復(fù)配置。例如,如果要使用 Spring 和 JPA 進(jìn)行數(shù)據(jù)庫(kù)訪問,在項(xiàng)目中引用 spring-boot-starter-data-jpa 即可。 分享一套SpringBoot開發(fā)博客系統(tǒng)源碼,以及完整開發(fā)文檔!速度保存! Spring 官方定義的 starter 通常命名遵循的格式為 spring-boot-starter-{name},例如 spring-boot-starter-web。非官方 starter 命名應(yīng)遵循 {name}-spring-boot-starter 的格式,例如,dubbo-spring-boot-starter。 需求寫一個(gè)序列化的插件,并且可以自由的選擇 fastjson 還是 gson,如果沒選的情況下默認(rèn)選擇 fastjson。 步驟1、 創(chuàng)建一個(gè) Spring Boot 項(xiàng)目,這里項(xiàng)目名字叫 jackformat-spring-boot-starter 2、引入依賴
3、先定義一個(gè)格式化的接口,分別寫兩個(gè)實(shí)現(xiàn)類 public interface FormatProcessor { 4、寫一個(gè)配置類,這里用了條件注解,如果 fastjson 和 gson 類存在的情況下才加載對(duì)應(yīng)的實(shí)現(xiàn)類,因?yàn)樵?pom 文件里都引用了,所以這里都會(huì)被裝載。注意這里紅框標(biāo)的 @Primary,對(duì)同一個(gè)接口,有幾種不同的實(shí)現(xiàn)類時(shí),@Autowired 是按類型注入的,不知道要選哪一個(gè),按照第二點(diǎn)需求,用戶在沒選的情況下默認(rèn)選擇 fastjson,所以這里給 fastjson 的實(shí)現(xiàn)上打上 @Primary。 5、配置類,用來讀取用戶的選擇,作用和 @Value 一樣,只是用了 jackxu.format 的前綴,這樣更方便。 6、序列化實(shí)現(xiàn)類,這個(gè)就是提供給用戶用來序列化用的,看名字 Template 大家也能知道,比如我們常用的 RedisTemplate、JdbcTemplate,構(gòu)造函數(shù)的時(shí)候直接傳入具體的實(shí)現(xiàn)。 7、好,現(xiàn)在就是最關(guān)鍵的主類了,我們從上往下看,@Import 之前說過了,導(dǎo)入配置類,就是將該配置類中的 Bean 注入到容器,@EnableConfigurationProperties 這是在將屬性類激活,注入到容器中,也可以用 @Bean 的方式,@Configuration 說明這是一個(gè)配置類。接下來將 FormatTemplate 注入到容器中,我們看到首先是去屬性類中去讀屬性,如果是 fastjson 就返回 fastjson 的實(shí)現(xiàn),如果是 gson 就返回 gson 的實(shí)現(xiàn),如果沒讀取到,就用前面設(shè)置的 @Primary 的默認(rèn)實(shí)現(xiàn)。 8、最后一步最關(guān)鍵的就是設(shè)置,在 resources 文件夾下創(chuàng)建 META-INF/spring.factories 文件,通過上面的知識(shí),Spring Boot 在啟動(dòng)的時(shí)候就是讀取該文件下的配置類,從而將 Bean 加載到容器中。 測(cè)試1、將自己的 starter 項(xiàng)目進(jìn)行 install 打包 2、測(cè)試項(xiàng)目中引用自己的 starter 3、寫一個(gè) controller,一個(gè)測(cè)試類,并把 formatTemplate 注入進(jìn)來 4、設(shè)置我們需要制定的序列化方式,這里選用 fastjson 5、啟動(dòng) Spring Boot 項(xiàng)目 6、通過瀏覽器訪問,發(fā)現(xiàn)這里顯示的是 fastjson 方式的序列化,成功了! 7、在測(cè)試 gson 的方式,返回了默認(rèn) gson 的實(shí)現(xiàn),也成功了! 8、最后測(cè)試用戶不選擇的情況下,默認(rèn)使用 fastjson,圓滿成功! 至此,本個(gè)需求已經(jīng)成功做出來了,我力求在做的過程中將手寫一個(gè) starter 所需用到的技術(shù)都講到,串聯(lián)起來,希望大家喜歡! 后記小伙伴們,Spring Boot 的使用中極大的簡(jiǎn)化了我們的使用,我也是 14 年畢業(yè)就開始用 SSM,那時(shí)候各種配置各種依賴,各種 XML 很是惡心。但是現(xiàn)在有了 Spring Boot 在幾分鐘內(nèi)就可以讓我們快速搭建一個(gè)項(xiàng)目跑起來,時(shí)代在變遷,也感謝讓我們?cè)絹碓奖憷?,在便利的過程中,我們還是要對(duì)底層的原理有一點(diǎn)的了解,而不是浮在上面只會(huì)使用,否則一但有問題找起來也不方便。 本文帶大家對(duì) Spring Boot 底層入了個(gè)門,還有 SringApplication 實(shí)例創(chuàng)建,設(shè)置初始化器和監(jiān)聽器,以及 run 方法里干的一些事,內(nèi)置 Tomcat 如何實(shí)現(xiàn)的,由于篇幅有限都沒有講,留給小伙伴自行研究。最后如果覺得寫得不錯(cuò),請(qǐng)點(diǎn)一個(gè)贊! (完) |
|