Java中SpringBoot自定義Starter詳解
什么是Starter
Starter是Spring Boot中的一個非常重要的概念,Starter相當于模塊,它能將模塊所需的依賴整合起來并對模塊內的Bean根據(jù)環(huán)境( 條件)進行自動配置。
使用者只需要依賴相應功能的Starter,無需做過多的配置和依賴,Spring Boot就能自動掃描并加載相應的模塊并設置默認值,做到開箱即用
為什么使用Starter
在我們的日常開發(fā)工作中,經(jīng)常會有一些獨立于業(yè)務之外的配置模塊,我們經(jīng)常將其放到一個特定的包下,然后如果另一個工程需要復用這塊功能的時候,需要將代碼硬拷貝到另一個工程,重新集成一遍,麻煩至極。
如果我們將這些可獨立于業(yè)務代碼之外的功配置模塊封裝成一個個starter,并在starter中設置好默認值,復用的時候只需要將其在pom中引用依賴即可,Spring Boot為我們完成自動裝配,做到開箱即用。
Springboot自動配置
SpringBoot中的starter是一種非常重要的機制,能夠拋棄以前繁雜的配置,將其統(tǒng)一集成進starter,應用者只需要在maven中引入starter依賴,Spring Boot就能自動掃描各個jar包下classpath路徑的spring.factories文件,加載自動配置類信息,加載相應的bean信息并啟動相應的默認配置。
Spring Boot提供了針對日常企業(yè)應用研發(fā)各種場景的spring-boot-starter依賴模塊。所有這些依賴模塊都遵循著約定成俗的默認配置,并允許我們調整這些配置,即遵循“約定大于配置”的理念。
spring.factories
Spring Boot會默認掃描跟啟動類平級的包,如果我們的Starter跟啟動類不在同一個主包下,需要通過配置spring.factories文件來配置生效,SpringBoot默認加載各個jar包下classpath路徑的spring.factories文件,配置的key為org.springframework.boot.autoconfigure.EnableAutoConfiguration
Starter開發(fā)常用注解
注解使用已經(jīng)大大方便我們開發(fā),再也不需要寫xml配置文件了,SpringBoot經(jīng)過查找spring.factories文件,加載自動配置類,而自動配置類中定義了各種運行時判斷條件,如@ConditionalOnMissingBean(A.class)等,只要ioc容器中沒有指定的A類型的bean信息,該配置文件才會生效。
@Conditional是Spring4新提供的注解,它的作用是按照一定的條件進行判斷,滿足條件給容器注冊bean。
- 屬性映射注解
- @ConfigurationProperties :配置文件屬性值和實體類的映射
- @EnableConfigurationProperties:和@ConfigurationProperties配合使用,把@ConfigurationProperties修飾的類加入ioc容器。
- 配置bean注解
- @Configuration :標識該類為配置類,并把該類注入ioc容器
- @Bean :一般在方法上使用,聲明一個bean,bean名稱默認是方法名稱,類型為返回值。
- 條件注解
- @Conditional:是根據(jù)條件類創(chuàng)建特定的Bean,條件類需要實現(xiàn)Condition接口,并重寫matches接口來構造判斷條件。
- @ConditionalOnBean :容器中存在指定bean,才會實例化一個Bean
- @ConditionalOnMissingBean:容器中不存在指定bean,才會實例化一個Bean
- @ConditionalOnClass:系統(tǒng)中有指定類,才會實例化一個Bean
- @ConditionalOnMissingClass:系統(tǒng)中沒有指定類,才會實例化一個Bean
- @ConditionalOnExpression:當SpEl表達式為true的時候,才會實例化一個Bean
- @AutoConfigureAfter :在某個bean完成自動配置后實例化這個bean
- @AutoConfigureBefore :在某個bean完成自動配置前實例化這個bean
- @ConditionalOnJava :系統(tǒng)中版本是否符合要求
- @ConditionalOnSingleCandidate:當指定的Bean在容器中只有一個,或者有多個但是指定了首選的Bean時觸發(fā)實例化
- @ConditionalOnResource:類路徑下是否存在指定資源文件
- @ConditionalOnWebApplication:是web應用
- @ConditionalOnNotWebApplication:不是web應用
- @ConditionalOnJndi:JNDI指定存在項
- @ConditionalOnProperty: 配置Configuration的加載規(guī)則
- prefix :配置屬性名稱的前綴
- value :數(shù)組,獲取對應property名稱的值,與name不可同時使用
- name :數(shù)組,可與prefix組合使用,組成完整的配置屬性名稱,與value不可同時使用
- havingValue :比較獲取到的屬性值與havingValue給定的值是否相同,相同才加載配置
- matchIfMissing :缺少該配置屬性時是否可以加載。如果為true,沒有該配置屬性時也會正常加載;反之則不會生效
Full全模式和Lite輕量級模式
- @Configuration參數(shù)proxyBeanMethods:
- Full 全模式(默認):
@Configuration(proxyBeanMethods = true)- 同一配置類下,當直接調用@Bean修飾的
方法注入的對象,則調用該方法會被代理,從ioc容器中取bean實列,所以實列是一樣的。即單實例對象,在該模式下SpringBoot每次啟動都會判斷檢查容器中是否存在該組件
- 同一配置類下,當直接調用@Bean修飾的
- Lite 輕量級模式:
@Configuration(proxyBeanMethods = false)- 同一配置類下,當直接調用@Bean修飾的
方法注入的對象,則調用該方法不會被代理,相當于直接調用一個普通方法,會有構造方法,但是沒有bean的生命周期,返回的是不同的實例。
- 同一配置類下,當直接調用@Bean修飾的
- Full 全模式(默認):
- 注:proxyBeanMethods 是為了讓使用@Bean注解的
方法被代理。而不是@Bean的單例多例的設置參數(shù)。 - 測試例子這里不展示,可以下載我的代碼查看
@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的啟動速度和性能
Starter命名規(guī)范
- Spring官方Starter通常命名為spring-boot-starter-{name}如:spring-boot-starter-web
- Spring官方建議非官方Starter命名應遵循{name}-spring-boot-starter的格式:如mybatis-spring-boot-starter。
開發(fā)Starter
1. 創(chuàng)建Starter項目

新建項目后,要刪除main啟動類
2. 添加依賴
<?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配置的元數(shù)據(jù),是json形式
3. 編寫屬性類
@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;
}
}
4. 自定義業(yè)務類
這里可以模擬一些獲取了配置文件信息的進行業(yè)務操作的業(yè)務類
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 +
'}';
}
}
5. 編寫自動配置類
命名規(guī)范:XxxAutoConfiguration
@Configuration(proxyBeanMethods = false)
// 當存在某個類時,此自動配置類才會生效
@ConditionalOnClass(value = {HelloService.class})
// 導入我們自定義的配置類,供當前類使用
@EnableConfigurationProperties(value = HelloProperties.class)
// 只有非web應用程序時此自動配置類才會生效
@ConditionalOnWebApplication
//判斷l(xiāng)jw.config.flag的值是否為“true”, matchIfMissing = true:沒有該配置屬性時也會正常加載
@ConditionalOnProperty(prefix = "ljw.config", name = "flag", havingValue = "true", matchIfMissing = true)
public class HelloAutoConfiguration {
/**
* @param helloProperties 直接方法簽名入?yún)⒆⑷際elloProperties,也可以使用屬性注入
* @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服務
6. 編寫spring.factories
把自動配置類HelloAutoConfiguration配置到org.springframework.boot.autoconfigure.EnableAutoConfiguration的key下,springboot會自動加載該文件并根據(jù)條件裝配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.ljw.starter.config.HelloAutoConfiguration
7. 編寫配置提示文件(非必須) additional-spring-configuration-metadata.json
配置additional-spring-configuration-metadata.json文件后,在開發(fā)人員的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表格進行配置上的理解。
| 名稱 | 類型 | 目的 |
| name | String | 屬性的全名。名稱采用小寫的周期分隔形式(例如server.address)。此屬性是強制性的。 |
| type | String | 屬性的數(shù)據(jù)類型的完整簽名(例如java.lang.String),但也是完整的泛型類型(例如java.util.Map<java.util.String,acme.MyEnum>)。您可以使用此屬性來指導用戶可以輸入的值的類型。為了保持一致性,通過使用其包裝對應項(例如,boolean變?yōu)閖ava.lang.Boolean)來指定基元的類型。請注意,此類可能是一個復雜類型,它從Stringas綁定的值轉換而來。如果類型未知或基本類型,則可以省略。 |
| description | String | 可以向用戶顯示的組的簡短描述。如果沒有可用的描述,則可以省略。建議描述為簡短段落,第一行提供簡明摘要。描述中的最后一行應以句點(.)結尾。 |
| sourceType | String | 貢獻此屬性的源的類名稱。例如,如果屬性來自帶注釋的類@ConfigurationProperties,則此屬性將包含該類的完全限定名稱。如果源類型未知,則可以省略。 |
| defaultValue | Object | 默認值,如果未指定屬性,則使用該值。如果屬性的類型是數(shù)組,則它可以是值數(shù)組。如果默認值未知,則可以省略。 |
| deprecation | 數(shù)組 | 過時的描述。 |
deprecation每個properties元素的屬性中包含的JSON對象可以包含以下屬性:
| 名稱 | 類型 | 目的 |
| level | String | 棄用級別,可以是warning(默認)或error。當屬性具有warning棄用級別時,它仍應綁定在環(huán)境中。但是,當它具有error棄用級別時,該屬性不再受管理且不受約束。 |
| reason | String | 該屬性被棄用的原因的簡短描述。如果沒有可用的原因,可以省略。建議描述為簡短段落,第一行提供簡明摘要。描述中的最后一行應以句點(.)結尾。 |
| replacement | String | 替換此不推薦使用的屬性的屬性的全名。如果此屬性沒有替換,則可以省略。 |
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": []
}測試Starter
1. 前置環(huán)境
install打包自定義starter項目
新建項目
2. 添加依賴
引入打好包的自定義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>3. 測試類
@Service
public class TestController implements CommandLineRunner {
/**
* 注入自定義starter服務
*/
@Resource
private HelloService helloService;
@Override
public void run(String... args) throws Exception {
System.out.println(helloService.hello());
}
}
4. 修改配置文件
輸入前綴可以看出已經(jīng)有提示了

ljw.config.name=ljw hello! ljw.config.age=99 ljw.config.flag=true #不會注入 #ljw.config.flag=true1 # 可以看到哪些自動配置了 debug=true
5. 運行程序打印
HelloService{name='ljw hello!', age=99}
- 條件注入
- 如果沒有spring-boot-starter-web依賴,不能注入服務HelloService
- 如果配置了ljw.config.flag,值不是true,不能注入服務HelloService;如果不配置ljw.config.flag,可以注入
6. 查看自動配置類生效的方法
通過啟用 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 a到此這篇關于Java中SpringBoot自定義Starter詳解的文章就介紹到這了,更多相關SpringBoot自定義Starter詳內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java使用Collections工具類對List集合進行排序
這篇文章主要介紹了Java使用Collections工具類對List集合進行排序,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-10-10
基于Java SSM實現(xiàn)Excel數(shù)據(jù)批量導入
這篇文章主要為大家詳細介紹了基于Java SSM如何實現(xiàn)excel數(shù)據(jù)批量導入,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-11-11
使用JAVA+Maven+TestNG框架實現(xiàn)超詳細Appium測試安卓真機教程
這篇文章主要介紹了使用JAVA+Maven+TestNG框架實現(xiàn)超詳細Appium測試安卓真機教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01
windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝教程
這篇文章主要介紹了windows10 JDK安裝及配置環(huán)境變量與Eclipse安裝,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2019-10-10

