在咱們學習SpringBoot
時都已經瞭解到starter
是SpringBoot
的核心組成部分,SpringBoot
爲咱們提供了儘量完善的封裝,提供了一系列的自動化配置的starter
插件,咱們在使用spring-boot-starter-web
時只須要在pom.xml
配置文件內添加依賴就能夠了,咱們以前傳統方式則是須要添加不少相關SpringMVC
配置文件。而spring-boot-starter-web
爲咱們提供了幾乎全部的默認配置,很好的下降了使用框架時的複雜度。
所以在使用xx.starter
時你就不用考慮該怎麼配置,即使是有一些必要的配置在application.properties
配置文件內對應配置就能夠了,那好,爲何我在application.properties
配置對應屬性後xx.starter
就能夠獲取到並做出處理呢?下面咱們帶着這個疑問來編寫咱們自定義的starter
讓咱們深刻了解SpringBoot
java
自定義starter
而且經過spring-boot-autoconfigure
完成自動化配置。git
建立starter
項目咱們並不須要建立SpringBoot
項目,咱們建立一個Maven
項目就能夠知足咱們的需求,建立項目完成後pom.xml
配置信息以下所示:web
<?xml version="1.0" encoding="UTF-8"?> <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>com.yuqiyu</groupId> <artifactId>chapter28</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>1.5.4.RELEASE</version> </dependency> </dependencies> </project>
咱們這個starter
並不作其餘複雜邏輯的編寫,因此這裏的依賴只是添加了spring-boot-autoconfigure
,實戰開發時能夠添加任意依賴到項目中。spring
咱們在文章開頭埋下了一個疑問,starter
是如何讀取application.properties
或者application.yml
配置文件內須要的配置參數的呢?那麼接下來咱們就看看如何能夠獲取自定義的配置信息。SpringBoot
在處理這種事情上早就已經考慮到了,因此提供了一個註解@ConfigurationProperties
,該註解能夠完成將application.properties
配置文件內的有規則的配置參數映射到實體內的field
內,不過須要提供setter方法,自定義配置參數實體代碼以下所示:apache
package com.yuqiyu.chapter28; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 配置文件實體映射 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/7/22 * Time:22:51 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @ConfigurationProperties(prefix = "hello") public class HelloProperties { //消息內容 private String msg = "HengYu"; //是否顯示消息內容 private boolean show = true; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public boolean isShow() { return show; } public void setShow(boolean show) { this.show = show; } }
在上面代碼中,@ConfigurationProperties
註解內咱們使用到了屬性preffix
,該屬性配置了讀取參數的前綴,根據上面的實體屬性對應配置文件內的配置則是hello.msg
、hello.show
,固然咱們提供了默認值,配置文件內不進行配置時則是使用默認值。springboot
咱們爲自定義starter
提供一個Service
,而且提供一個名爲sayHello
的方法用於返回咱們配置的msg
內容。代碼以下所示:app
package com.yuqiyu.chapter28; /** * 自定義業務實現 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/7/22 * Time:22:54 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ public class HelloService { //消息內容 private String msg; //是否顯示消息內容 private boolean show = true; public String sayHello() { return show ? "Hello," + msg : "Hidden"; } public void setMsg(String msg) { this.msg = msg; } public void setShow(boolean show) { this.show = show; } }
咱們Service
內的代碼比較簡單,根據屬性參數進行返回格式化後的字符串。框架
接下來咱們開始編寫自動配置,這一塊是starter
的核心部分,配置該部分後在啓動項目時纔會自動加載配置,固然其中有不少細節性質的配置less
自動化配置其實只是提供實體bean的驗證以及初始化,咱們先來看看代碼:maven
package com.yuqiyu.chapter28; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * 自定義starter自動化配置 * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/7/22 * Time:22:56 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @Configuration//開啓配置 @EnableConfigurationProperties(HelloProperties.class)//開啓使用映射實體對象 @ConditionalOnClass(HelloService.class)//存在HelloService時初始化該配置類 @ConditionalOnProperty//存在對應配置信息時初始化該配置類 ( prefix = "hello",//存在配置前綴hello value = "enabled",//開啓 matchIfMissing = true//缺失檢查 ) public class HelloAutoConfiguration { //application.properties配置文件映射前綴實體對象 @Autowired private HelloProperties helloProperties; /** * 根據條件判斷不存在HelloService時初始化新bean到SpringIoc * @return */ @Bean//建立HelloService實體bean @ConditionalOnMissingBean(HelloService.class)//缺失HelloService實體bean時,初始化HelloService並添加到SpringIoc public HelloService helloService() { System.out.println(">>>The HelloService Not Found,Execute Create New Bean."); HelloService helloService = new HelloService(); helloService.setMsg(helloProperties.getMsg());//設置消息內容 helloService.setShow(helloProperties.isShow());//設置是否顯示 return helloService; } }
自動化配置代碼中有不少咱們以前沒有用到的註解配置,咱們從上開始講解
@Configuration
:這個配置就不用多作解釋了,咱們一直在使用@EnableConfigurationProperties
:這是一個開啓使用配置參數的註解,value
值就是咱們配置實體參數映射的ClassType
,將配置實體做爲配置來源。
有關@ConditionalOnXxx
相關的註解這裏要系統的說下,由於這個是咱們配置的關鍵,根據名稱咱們能夠理解爲具備Xxx條件
,固然它實際的意義也是如此,條件註解是一個系列,下面咱們詳細作出解釋
@ConditionalOnBean
:當SpringIoc
容器內存在指定Bean
的條件@ConditionalOnClass
:當SpringIoc
容器內存在指定Class
的條件@ConditionalOnExpression
:基於SpEL表達式做爲判斷條件@ConditionalOnJava
:基於JVM
版本做爲判斷條件@ConditionalOnJndi
:在JNDI存在時查找指定的位置@ConditionalOnMissingBean
:當SpringIoc
容器內不存在指定Bean
的條件@ConditionalOnMissingClass
:當SpringIoc
容器內不存在指定Class
的條件@ConditionalOnNotWebApplication
:當前項目不是Web項目的條件@ConditionalOnProperty
:指定的屬性是否有指定的值@ConditionalOnResource
:類路徑是否有指定的值@ConditionalOnSingleCandidate
:當指定Bean
在SpringIoc
容器內只有一個,或者雖然有多個可是指定首選的Bean
@ConditionalOnWebApplication
:當前項目是Web項目的條件
以上註解都是元註解@Conditional
演變而來的,根據不用的條件對應建立以上的具體條件註解。
到目前爲止咱們尚未完成自動化配置starter
,咱們須要瞭解SpringBoot
運做原理後才能夠完成後續編碼。
在註解@SpringBootApplication
上存在一個開啓自動化配置的註解@EnableAutoConfiguration
來完成自動化配置,註解源碼以下所示:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package org.springframework.boot.autoconfigure; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.context.annotation.Import; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import({EnableAutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration { String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration"; Class<?>[] exclude() default {}; String[] excludeName() default {}; }
在@EnableAutoConfiguration
註解內使用到了@import
註解來完成導入配置的功能,而EnableAutoConfigurationImportSelector
內部則是使用了SpringFactoriesLoader.loadFactoryNames
方法進行掃描具備META-INF/spring.factories
文件的jar包。咱們能夠先來看下spring-boot-autoconfigure
包內的spring.factories
文件內容,以下所示:
# Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\ org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.autoconfigure.BackgroundPreinitializer # Auto Configuration Import Listeners org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\ org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener # Auto Configuration Import Filters org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ org.springframework.boot.autoconfigure.condition.OnClassCondition # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\ org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\ .....省略
能夠看到配置的結構形式是Key
=>Value
形式,多個Value
時使用,
隔開,那咱們在自定義starter
內也能夠使用這種形式來完成,咱們的目的是爲了完成自動化配置,因此咱們這裏Key
則是須要使用org.springframework.boot.autoconfigure.EnableAutoConfiguration
咱們在src/main/resource
目錄下建立META-INF
目錄,並在目錄內添加文件spring.factories
,具體內容以下所示:
#配置自定義Starter的自動化配置 org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.yuqiyu.chapter28.HelloAutoConfiguration
都目前爲止咱們的自定義starter
已經配置完成,下面咱們須要新建一個SpringBoot
項目來測試咱們的自動化配置是否已經生效。
在使用自定義starter
以前須要將starter
做Maven Jar Install
到本地,咱們使用idea工具自帶的maven命令完成該操做
步驟:工具右側 -> Maven Projects -> Lifecycle -> install
建立測試項目的pom.xml
配置文件內容以下所示:
<?xml version="1.0" encoding="UTF-8"?> <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>com.yuqiyu.sample</groupId> <artifactId>test-spring-boot-starter-hello</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>test-spring-boot-starter-hello</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--自定義starter依賴--> <dependency> <groupId>com.yuqiyu</groupId> <artifactId>chapter28</artifactId> <version>1.0.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
咱們只須要將依賴添加到pom.xml
配置文件內
在運行項目以前,咱們打開application.properties
配置文件開啓debug
模式,查看自動化配置的輸出日誌,配置內容以下所示:
#顯示debug日誌信息 debug=true
接下來咱們啓動項目,在控制檯查找是否存在咱們的HelloAutoConfiguration
日誌輸出,控制檯輸出內容以下所示:
.....省略 >>>The HelloService Not Found,Execute Create New Bean. .....省略 HelloAutoConfiguration matched: - @ConditionalOnClass found required class 'com.yuqiyu.chapter28.HelloService'; @ConditionalOnMissingClass did not find unwanted class (OnClassCondition) - @ConditionalOnProperty (hello.enabled) matched (OnPropertyCondition) HelloAutoConfiguration#helloService matched: - @ConditionalOnMissingBean (types: com.yuqiyu.chapter28.HelloService; SearchStrategy: all) did not find any beans (OnBeanCondition) .....省略
在控制檯能夠看到咱們的自定義starter
的自動化配置已經生效了,而且根據@ConditionalOnMissingBean(HelloService.class)
作出了條件注入HelloService
實體bean到SpringIoc
容器內
咱們來編寫一個簡單的測試控制器,查看HelloService
在不配置參數狀況下輸出格式化字符串內容,控制器代碼以下所示:
package com.yuqiyu.sample.testspringbootstarterhello; import com.yuqiyu.chapter28.HelloService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 測試自定義starter自動化配置HelloService * ======================== * Created with IntelliJ IDEA. * User:恆宇少年 * Date:2017/7/23 * Time:11:42 * 碼雲:http://git.oschina.net/jnyqy * ======================== */ @RestController public class HelloController { //注入自定義starter內邏輯 @Autowired HelloService helloService; /** * 測試訪問地址/hello * @return 格式化字符串 */ @RequestMapping(value = "/hello") public String sayHello() { return helloService.sayHello(); } }
接下來咱們重啓下項目,訪問地址http://127.0.0.1:8080/hello,界面輸出內容以下所示:
Hello,HengYu
界面輸出的內容是咱們默認值,接下來咱們在application.properties
配置文件內對應添加hello.msg
、hello.show
配置參數,以下所示:
#配置自定義starter參數 hello.msg=HengYu Boy hello.show=true
重啓項目,再次訪問地址,界面輸出內容以下所示:
Hello,HengYu Boy
咱們的配置生效了,到目前爲止我相信你們已經明白了咱們application.properties
配置文件爲何能夠做爲統一配置入口,爲何配置後能夠被對應starter
所使用。
以上內容是本章的所有講解,本章主要講解了咱們如何自定義starter
而且自動化配置到SpringBoot
項目中,固然裏面還有不少神奇的地方須要你們去深刻挖掘。
本章代碼已經上傳到碼雲:
網頁地址:http://git.oschina.net/jnyqy/lessons
Git地址:https://git.oschina.net/jnyqy/lessons.git
SpringBoot相關係列文章請訪問:目錄:SpringBoot學習目錄
QueryDSL相關係列文章請訪問:QueryDSL通用查詢框架學習目錄
感謝閱讀!
歡迎加入QQ技術交流羣,共同進步。QQ技術交流羣