您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關SpringBoot怎么自定義Starter的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
Starter是Spring Boot中的一個非常重要的概念,Starter相當于模塊,它能將模塊所需的依賴整合起來并對模塊內的Bean根據環境( 條件)進行自動配置。
使用者只需要依賴相應功能的Starter,無需做過多的配置和依賴,Spring Boot就能自動掃描并加載相應的模塊并設置默認值,做到開箱即用
在我們的日常開發工作中,經常會有一些獨立于業務之外的配置模塊,我們經常將其放到一個特定的包下,然后如果另一個工程需要復用這塊功能的時候,需要將代碼硬拷貝到另一個工程,重新集成一遍,麻煩至極。
如果我們將這些可獨立于業務代碼之外的功配置模塊封裝成一個個starter,并在starter中設置好默認值,復用的時候只需要將其在pom中引用依賴即可,Spring Boot為我們完成自動裝配,做到開箱即用。
SpringBoot中的starter是一種非常重要的機制,能夠拋棄以前繁雜的配置,將其統一集成進starter,應用者只需要在maven中引入starter依賴,Spring Boot就能自動掃描各個jar包下classpath路徑的spring.factories文件,加載自動配置類信息,加載相應的bean信息并啟動相應的默認配置。
Spring Boot提供了針對日常企業應用研發各種場景的spring-boot-starter依賴模塊。所有這些依賴模塊都遵循著約定成俗的默認配置,并允許我們調整這些配置,即遵循“約定大于配置”的理念。
大家可以看看我之前寫的一篇文章,詳細介紹了springboot自動配置的流程:一文搞懂SpringBoot自動配置原理
Spring Boot會默認掃描跟啟動類平級的包,如果我們的Starter跟啟動類不在同一個主包下,需要通過配置spring.factories文件來配置生效,SpringBoot默認加載各個jar包下classpath路徑的spring.factories文件,配置的key為org.springframework.boot.autoconfigure.EnableAutoConfiguration
注解使用已經大大方便我們開發,再也不需要寫xml配置文件了,SpringBoot經過查找spring.factories文件,加載自動配置類,而自動配置類中定義了各種運行時判斷條件,如@ConditionalOnMissingBean(A.class)等,只要ioc容器中沒有指定的A類型的bean信息,該配置文件才會生效。
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進行判斷,滿足條件給容器注冊bean。
1.屬性映射注解
@ConfigurationProperties :配置文件屬性值和實體類的映射
@EnableConfigurationProperties:和@ConfigurationProperties配合使用,把@ConfigurationProperties修飾的類加入ioc容器。
2.配置bean注解
@Configuration :標識該類為配置類,并把該類注入ioc容器
@Bean :一般在方法上使用,聲明一個bean,bean名稱默認是方法名稱,類型為返回值。
3.條件注解
@Conditional:是根據條件類創建特定的Bean,條件類需要實現Condition接口,并重寫matches接口來構造判斷條件。
@ConditionalOnBean :容器中存在指定bean,才會實例化一個Bean
@ConditionalOnMissingBean:容器中不存在指定bean,才會實例化一個Bean
@ConditionalOnClass:系統中有指定類,才會實例化一個Bean
@ConditionalOnMissingClass:系統中沒有指定類,才會實例化一個Bean
@ConditionalOnExpression:當SpEl表達式為true的時候,才會實例化一個Bean
@AutoConfigureAfter :在某個bean完成自動配置后實例化這個bean
@AutoConfigureBefore :在某個bean完成自動配置前實例化這個bean
@ConditionalOnJava :系統中版本是否符合要求
@ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者有多個但是指定了首選的Bean時觸發實例化
@ConditionalOnResource:類路徑下是否存在指定資源文件
@ConditionalOnWebApplication:是web應用
@ConditionalOnNotWebApplication:不是web應用
@ConditionalOnJndi:JNDI指定存在項
@ConditionalOnProperty: 配置Configuration的加載規則
prefix :配置屬性名稱的前綴
value :數組,獲取對應property名稱的值,與name不可同時使用
name :數組,可與prefix組合使用,組成完整的配置屬性名稱,與value不可同時使用
havingValue :比較獲取到的屬性值與havingValue給定的值是否相同,相同才加載配置
matchIfMissing :缺少該配置屬性時是否可以加載。如果為true,沒有該配置屬性時也會正常加載;反之則不會生效
@Configuration參數proxyBeanMethods:
Full 全模式(默認):@Configuration(proxyBeanMethods = true)
同一配置類下,當直接調用@Bean修飾的方法注入的對象,則調用該方法會被代理,從ioc容器中取bean實列,所以實列是一樣的。即單實例對象,在該模式下SpringBoot每次啟動都會判斷檢查容器中是否存在該組件
Lite 輕量級模式:@Configuration(proxyBeanMethods = false)
同一配置類下,當直接調用@Bean修飾的方法注入的對象,則調用該方法不會被代理,相當于直接調用一個普通方法,會有構造方法,但是沒有bean的生命周期,返回的是不同的實例。
注:proxyBeanMethods 是為了讓使用@Bean注解的方法被代理。而不是@Bean的單例多例的設置參數。
測試例子這里不展示,可以下載我的代碼查看
@Configuration(proxyBeanMethods = false) public class AppConfig { //放一份myBean到ioc容器 @Bean public Mybean myBean() { return new Mybean(); } //放一份yourBean到ioc容器 @Bean public YourBean yourBean() { System.out.println("=========="); //注意:@Configuration(proxyBeanMethods = false):myBean()方法不代理,直接調用 //注意:@Configuration(proxyBeanMethods = true):myBean()方法代理,從ioc容器拿 return new YourBean(myBean()); } }
什么時候用Full全模式,什么時候用Lite輕量級模式?
當在你的同一個Configuration配置類中,注入到容器中的bean實例之間有依賴關系時,建議使用Full全模式
當在你的同一個Configuration配置類中,注入到容器中的bean實例之間沒有依賴關系時,建議使用Lite輕量級模式,以提高springboot的啟動速度和性能
Spring官方Starter通常命名為spring-boot-starter-{name}如:spring-boot-starter-web
Spring官方建議非官方Starter命名應遵循{name}-spring-boot-starter的格式:如mybatis-spring-boot-starter。
新建項目后,要刪除main啟動類
<?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"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.ljw</groupId> <artifactId>ljw-spring-boot-starter</artifactId> <version>1.0</version> <properties> <java.version>1.8</java.version> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 包含自動配置的代碼--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <!-- 配置文件點擊可以跳轉實體--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> </project>
我們沒有main入口,需要去除pom文件中maven打包插件spring-boot-maven-plugin
spring-boot-configuration-processor作用:
spring-boot-configuration-processor其實是一個注解處理器,在編譯階段干活的,一般在maven的聲明都是optional 為true
你在idea里面可以點擊port,進到這個字段里面,還可以看到配置的提示信息
這是因為在你的資源文件里面有一個spring-configuration-metadata.json文件,這是spring配置的元數據,是json形式
@ConfigurationProperties可以定義一個配置信息類,和配置文件進行映射
@ConfigurationProperties(prefix = "ljw.config") public class HelloProperties { private String name = "hello 默認值!"; private int age = 8; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
這里可以模擬一些獲取了配置文件信息的進行業務操作的業務類
public class HelloService { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String hello() { return "HelloService{" + "name='" + name + ''' + ", age=" + age + '}'; } }
命名規范:XxxAutoConfiguration
@Configuration(proxyBeanMethods = false) // 當存在某個類時,此自動配置類才會生效 @ConditionalOnClass(value = {HelloService.class}) // 導入我們自定義的配置類,供當前類使用 @EnableConfigurationProperties(value = HelloProperties.class) // 只有非web應用程序時此自動配置類才會生效 @ConditionalOnWebApplication //判斷ljw.config.flag的值是否為“true”, matchIfMissing = true:沒有該配置屬性時也會正常加載 @ConditionalOnProperty(prefix = "ljw.config", name = "flag", havingValue = "true", matchIfMissing = true) public class HelloAutoConfiguration { /** * @param helloProperties 直接方法簽名入參注入HelloProperties,也可以使用屬性注入 * @return */ @Bean @ConditionalOnMissingBean(HelloService.class) //@ConditionalOnProperty(prefix = "ljw.config", name = "flag", havingValue = "true", matchIfMissing = true) public HelloService helloService(HelloProperties helloProperties) { HelloService helloService = new HelloService(); //把獲取的信息注入 helloService.setName(helloProperties.getName()); helloService.setAge(helloProperties.getAge()); return helloService; } }
注:這里配置一個web應用才能注入,并且ljw.config.flag的值是否為“true”或者不配置該key才能注入HelloService服務
把自動配置類HelloAutoConfiguration配置到org.springframework.boot.autoconfigure.EnableAutoConfiguration的key下,springboot會自動加載該文件并根據條件裝配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ljw.starter.config.HelloAutoConfiguration
additional-spring-configuration-metadata.json
配置additional-spring-configuration-metadata.json文件后,在開發人員的IDE工具使用個人編寫的配置讀取很有效的在application.properties或application.yml文件下完成提示。
配置詳細格式參數可查看文檔
我的配置:
{"properties": [ { "name": "ljw.config.name", "type": "java.lang.String", "defaultValue": "hello 默認值!這里配置的是提示,真正默認值在Properties里面", "description": "這是字符串名稱啊." }, { "name": "ljw.config.age", "defaultValue": 8, "description": "這是int類型的年齡啊.", "deprecation": { "reason": "過時原因.", "replacement": "替代key是:ljw.config.age22", "level": "warning" } } ]}
大家參考下面properties表格進行配置上的理解。
deprecation每個properties元素的屬性中包含的JSON對象可以包含以下屬性:
spring-configuration-metadata.json
spring-configuration-metadata.json代碼量挺大的,為了方便我們可以通過IDE來生成,這里使用的是idea。
在idea設置中搜索Annotation Processors,接下來勾住Enable annonation processing就完成了。在編譯打包后的文件中看到自動生成的spring-configuration-metadata.json。這個文件不用我們編寫
下面是自動生成的:
{ "groups": [ { "name": "ljw.config", "type": "com.ljw.starter.properties.HelloProperties", "sourceType": "com.ljw.starter.properties.HelloProperties" } ], "properties": [ { "name": "ljw.config.name", "type": "java.lang.String", "description": "這是字符串名稱啊.", "sourceType": "com.ljw.starter.properties.HelloProperties", "defaultValue": "hello 默認值!這里配置的是提示,真正默認值在Properties里面" }, { "name": "ljw.config.age", "type": "java.lang.Integer", "description": "這是int類型的年齡啊.", "sourceType": "com.ljw.starter.properties.HelloProperties", "defaultValue": 8, "deprecated": true, "deprecation": { "level": "warning", "reason": "過時原因.", "replacement": "替代key是:ljw.config.age22" } } ], "hints": [] }
install打包自定義starter項目:ljw-spring-boot-starter
新建項目:ljw-test-spring-boot-starter
引入打好包的自定義starter
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 測試web應用--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--自定義satrter--> <dependency> <groupId>com.ljw</groupId> <artifactId>ljw-spring-boot-starter</artifactId> <version>1.0</version> </dependency> </dependencies>
@Service public class TestController implements CommandLineRunner { /** * 注入自定義starter服務 */ @Resource private HelloService helloService; @Override public void run(String... args) throws Exception { System.out.println(helloService.hello()); } }
輸入前綴可以看出已經有提示了
ljw.config.name=ljw hello! ljw.config.age=99 ljw.config.flag=true #不會注入 #ljw.config.flag=true1 # 可以看到哪些自動配置了 debug=true
HelloService{name='ljw hello!', age=99}
條件注入
如果沒有spring-boot-starter-web依賴,不能注入服務HelloService
如果配置了ljw.config.flag,值不是true,不能注入服務HelloService;如果不配置ljw.config.flag,可以注入
通過啟用 debug=true 屬性,讓控制臺打印自動配置報告,這樣就可以很方便地知道哪些自動配置類生效。
HelloAutoConfiguration matched: - @ConditionalOnClass found required class 'com.ljw.starter.service.HelloService' (OnClassCondition) - @ConditionalOnWebApplication (required) found 'session' scope (OnWebApplicationCondition) - @ConditionalOnProperty (ljw.config.flag=true) matched (OnPropertyCondition) HelloAutoConfiguration#helloService matched: - @ConditionalOnMissingBean (types: com.ljw.starter.service.HelloService; SearchStrategy: all) did not find any beans (OnBeanCondition)
感謝各位的閱讀!關于“SpringBoot怎么自定義Starter”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。