詳解SpringBoot如何創(chuàng)建自定義Starter
Spring Boot的自動配置機制為開發(fā)人員提供了一種輕松集成和配置各種功能的便捷方式。然而,隨著項目的復雜性增加,更好地組織和分享通用功能變得至關重要。自定義Starter成為了理想的解決方案,旨在簡化項目的依賴管理和自動配置,使開發(fā)者能夠迅速而靈活地集成特定的功能模塊。本文將深入探討在Spring Boot中如何創(chuàng)建自定義Starter,為構建模塊化且易維護的應用提供有力的支持。
接下來我們來實現一個自定義的starter
。
實現自定義Starter
首先,我們需要明確自定義starter的目標功能,如提供特定領域的服務或集成第三方庫。比如我們創(chuàng)建一個coderacademy-spring-boot-starter
的starter,用于提供某些服務。例如我們的服務就實現一個打印功能:
public class CoderAcademyService { public String sayHello(){ return "Hello 碼農Academy!"; } }
本文旨在介紹如何自定義starter,故而starter的功能不是本文的主要內容,后續(xù)我們會提供一個基于注解實現ES操作/搜索的服務的starter。感興趣的,點個關注哦~
創(chuàng)建項目結構
我們創(chuàng)建一個名為springboot-coderacademy-starter
的項目,在pom.xml
中設置groupId
,artifactId
還有version
。其中groupId
與artifactId
應反映starter的名稱。
<groupId>com.springboot.coderacaemy</groupId> <artifactId>coderacermy-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging>
然后我們在引入一些我們需要是用到的依賴,比如我們要使用@Configuration
,@EnableConfigurationProperties
等注解:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.0</version> </parent> <groupId>com.springboot.coderacaemy</groupId> <artifactId>coderacermy-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-starter</name> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <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>
其中spring-boot-configuration-processor
這個依賴主要用于IDEA支持和編譯時生成元數據。
本文使用的springboot版本為2.7.0
創(chuàng)建自動配置類
自動配置類負責定義Spring Boot應用程序中的通用配置和功能。這個類通常使用@Configuration
注解進行標記,在這個類中注入服務、組件或其他你需要自動配置的對象。
import com.springboot.starter.coderacademy.service.CoderAcademyService; import org.springframework.context.annotation.Configuration; /** * @version 1.0 * @description: <p></p > * @author: 碼農Academy * @create: 2024/1/31 14:38 */ @Configuration public class CoderAcademyAutoConfig { @Bean public CoderAcademyService coderAcademyService(){ return new CoderAcademyService(); } }
指定自動裝配類
在resources
文件夾下創(chuàng)建一個META-INF/spring.factories
文件,在這個文件中指定自動裝配類CoderAcademyAutoConfig
:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.springboot.starter.coderacademy.config.CoderAcademyAutoConfig
在META-INF/spring.factories
文件中,org.springframework.boot.autoconfigure.EnableAutoConfiguration
是一個特殊的鍵,它的值是一個包含要應用的自動配置類的全限定名列表。當應用啟動時,SpringBoot的引導過程會掃描所有已引入jar包中的spring.factories
文件,并根據EnableAutoConfiguration
鍵下的類來加載和執(zhí)行相應的自動配置邏輯。
當然如果不使用這個配置,在調用方使用@ComponentScan
也可以掃描到CoderAcademyAutoConfig
。但是這跟Starter的設計理念相悖。在Starter的設計中,一般不推薦調用方手動進行額外的掃描。這是因為調用方引入了Starter,就應該依賴于 Starter提供的自動配置。手動掃描可能會導致不必要的麻煩,例如循環(huán)依賴、配置類的重復加載等問題。
假如我們現在沒有其他的配置了,比如說一下額外的屬性配置,那我們就可以打包與發(fā)布了。
打包與發(fā)布
此時我們就可以將自定義Starter打包,并發(fā)布到Maven倉庫或其他倉庫管理工具。
本地開發(fā)時,可以直接install。不必發(fā)不到私服。
測試
我們新建一個調用方的項目,在其中引入coderacademy-spring-boot-starter
。
<dependency> <groupId>com.springboot.coderacaemy</groupId> <artifactId>coderacermy-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
我們編寫測試類:
@SpringBootTest class SpringbootCodeApplicationTests { private CoderAcademyService coderAcademyService; @Test public void testCoderAcademy(){ String str = coderAcademyService.sayHello(); System.out.println(str); } @Autowired public void setCoderAcademyService(CoderAcademyService coderAcademyService) { this.coderAcademyService = coderAcademyService; } }
執(zhí)行結果如下:
這樣一個很簡單的Starter就完成了。
當然在實際開發(fā)中,我們還需要一些自定義配置項需要注入到Starter中,才可以提供完整的服務。
配置屬性
我們新建一個CoderAcademyProperties
類用于接收,調用方在自己項目中的application.yaml
或者其他的配置中心配置的信息。
@ConfigurationProperties(prefix = "coderacademy") public class CoderAcademyProperties { private String name = "碼農Academy"; public String getName() { return name; } public void setName(String name) { this.name = name; } }
@ConfigurationProperties
是 SpringBoot中用于綁定外部配置到Bean的屬性上,prefix
屬性指定了配置前綴。這樣我們就可以在調用方的application.yml
中配置以coderacademy
為前綴的信息。這里我們也給了默認值。
然后我們將這個配置注入到CoderAcademyService
中去。
public class CoderAcademyService { private final CoderAcademyProperties coderAcademyProperties; public String sayHello(){ return "Hello "+ coderAcademyConfig.getName(); } public CoderAcademyService(CoderAcademyProperties coderAcademyProperties) { this.coderAcademyProperties = coderAcademyProperties; } }
我們改動一下CoderAcademyService
的AutoConfig。
@EnableConfigurationProperties({CoderAcademyProperties.class}) @Configuration public class CoderAcademyAutoConfig { @Bean public CoderAcademyService coderAcademyService(CoderAcademyProperties coderAcademyProperties){ return new CoderAcademyService(coderAcademyProperties); } }
我重新Deploy
之后,然后在調用方配置一下CoderAcademyProperties
中對應的屬性:
coderacademy.name = CoderAcademy
再次跑一下單測:
在實際開發(fā)場景中,我們有時會遇到這樣的需求:調用方希望根據自身項目的需求靈活定義配置項,無需嚴格遵循CoderAcademyProperties
中預設的模式(例如coderacademy.name
)。例如,他們可能傾向于通過自定義屬性customer.starter.name
來代替,并將這個屬性值映射到其項目的配置文件中。隨后,在調用方自己的@Configuration
類里,基于這些個性化配置來創(chuàng)建一個CoderAcademyService
實例。
然而,問題在于,Starter模塊內部預先提供了一個默認的CoderAcademyService
Bean定義。當調用方在其應用上下文中也聲明了同類型的Bean時,這將觸發(fā)Spring容器中的Bean沖突和初始化異常。為了解決這個問題,我們在設計Starter
時需要考慮到這一點,我們在自動配置類中利用@ConditionalOnMissingBean
注解來確保僅在容器中尚無CoderAcademyService
Bean時才進行創(chuàng)建操作。這樣就避免了重復注冊同一類型Bean導致的問題。
@EnableConfigurationProperties({CoderAcademyProperties.class}) @Configuration @ConditionalOnMissingBean(CoderAcademyService.class) public class CoderAcademyAutoConfig { @Bean public CoderAcademyService coderAcademyService(CoderAcademyProperties coderAcademyProperties){ return new CoderAcademyService(coderAcademyProperties); } }
然后我們在調用方設計一個配置類,用于創(chuàng)建一個CoderAcademyService
。
@Configuration public class CustomerConfig { @Value("${customer.coderacademy.name}") private String customerName; @Bean public CoderAcademyService coderAcademyService(){ CoderAcademyProperties properties = new CoderAcademyProperties(); properties.setName(customerName); return new CoderAcademyService(properties); } }
在調用方的application.properties
加上customer.coderacademy.name
配置。
customer.coderacademy.name = customer,coderacademy
我們再次在調用方執(zhí)行:
屬性配置提示
我們在使用其他的官方Starter
時在application.properties
或者application.yml
配置相關屬性時,IDEA會自動給出屬性的Key的提示,以及給出默認值。那么在自定義Starter
中該如何實現這功能呢?其實這就需要用到了我們引入的spring-boot-configuration-processor
依賴。
spring-boot-configuration-processor
是 Spring Boot 提供的一個注解處理器,用于處理 @ConfigurationProperties
注解,生成配置屬性的元數據,以提供更好的 IDE 支持和配置文件提示。注解處理器會掃描項目中標注了@ConfigurationProperties
注解的類,然后生成包含有關這些配置屬性的詳細信息的 spring-configuration-metadata.json
文件。該文件位于META-INF
下。這個元數據文件包含了配置屬性的描述、類型、默認值等信息,以提供更好的代碼提示和文檔生成功能。元數據文件被 IDE(如 IDEA、Eclipse)使用,用于提供更強大的代碼提示和補全功能。開發(fā)者在編輯配置文件時可以看到配置屬性的描述、類型等信息,更容易正確地配置應用程序。
當然添加依賴之后,我們還需要添加Maven的插件(如果使用的是Maven)。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.7.0</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build>
然后我們執(zhí)行mvn clean -U install -DskipTests
命令后,就可以在target下的META-INF
就可以看見這個元數據文件。
我們在重新打包之后,在調用方的application.properties
中配置屬性信息時,可以看到效果:
配置文件默認值
在上述示例中,我們在CoderAcademyProperties
代碼中顯示的給name
賦值了一個默認值。這種方式實現也可以,但是不夠優(yōu)雅,我們換一種優(yōu)雅的方式去實現配置的默認值設置。我們該用設置一個存儲默認值的配置文件coderacademy-default.properties
,從這個文件綁定配置的默認值。
我們在resources/META-INF
下創(chuàng)建一個coderacademy-default.properties
。
coderacademy.name = Default CoderAcademy
然后在CoderAcademyAutoConfig
中使用@PropertySource
將這這個默認文件中的配置加載綁定到Bean中即CoderAcademyProperties
中。
@AutoConfigureAfter({CoderAcademyPropertiesAutoConfig.class}) @EnableConfigurationProperties({CoderAcademyProperties.class}) @Configuration @ConditionalOnMissingBean(CoderAcademyService.class) @PropertySource(name = "CoderAcademy Default Properties", value = "classpath:/META-INF/coderacademy-default.properties") public class CoderAcademyAutoConfig { @Bean public CoderAcademyService coderAcademyService(CoderAcademyProperties coderAcademyProperties){ return new CoderAcademyService(coderAcademyProperties); } }
在SpringBoot應用中,通過application.properties
或application.yml
設置的屬性具有較高的優(yōu)先級。如果使用@PropertySource
加載的屬性與前者有沖突,則會被后者覆蓋。
我們在調用方直接使用Starter
中創(chuàng)建的CoderAcademyService
,看一下效果:
即此時使用的是coderacademy-default.properties
中配置的默認值。
我們在調用方配置coderacademy.name
的值
coderacademy.name = This is CoderAcademy
再次運行一下數據
至此一個自定義的Starter
就完成了。
示例
項目架構:
依賴:
<?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.0</version> </parent> <groupId>com.springboot.coderacaemy</groupId> <artifactId>coderacermy-spring-boot-starter</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-starter</name> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <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> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <annotationProcessorPaths> <path> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>2.7.0</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> </project>
- 服務配置信息
@ConfigurationProperties(prefix = "coderacademy") public class CoderAcademyProperties { private String url; private Integer port; private String userName; private String password; // 省略get set方法 }
CoderAcademyProperties
主要作用是為了綁定application.properites
中配置信息。其默認的配置文件coderacademy-default.properties
:
coderacademy.url=https://www.coderacademy.online/ coderacademy.port=8080 coderacademy.user-name=CoderAcademy coderacademy.password=123456
- 服務配置類
新建一個CoderAcademyConfig
用于創(chuàng)建CoderAcademyService
服務。CoderAcademyProperties
只作為服務的配置信息,主要參與綁定外部配置文件中的配置信息。
public class CoderAcademyConfig { private String url; private Integer port; private String userName; private String password; // 省略 get set }
在創(chuàng)建一個將CoderAcademyProperties
的參數綁定到配置類CoderAcademyConfig
的一個自動裝配類CoderAcademyPropertiesAutoConfig
。
@Configuration @EnableConfigurationProperties({CoderAcademyProperties.class}) @PropertySource(name = "CoderAcademy Default Properties", value = "classpath:/META-INF/coderacademy-default.properties") public class CoderAcademyPropertiesAutoConfig { @Bean public CoderAcademyConfig coderAcademyConfig(CoderAcademyProperties coderAcademyProperties){ CoderAcademyConfig coderAcademyConfig = new CoderAcademyConfig(); coderAcademyConfig.setPort(coderAcademyProperties.getPort()); coderAcademyConfig.setUrl(coderAcademyProperties.getUrl()); coderAcademyConfig.setPassword(coderAcademyProperties.getPassword()); coderAcademyConfig.setUserName(coderAcademyProperties.getUserName()); return coderAcademyConfig; } }
- 服務類
服務類中就是用CoderAcademyConfig
創(chuàng)建。
public class CoderAcademyService { private final CoderAcademyConfig coderAcademyConfig; public String connectDB(){ return "Connect to " + coderAcademyConfig.getUrl() + ":" + coderAcademyConfig.getPort() + " successfully!"; } public CoderAcademyService(CoderAcademyConfig coderAcademyConfig) { this.coderAcademyConfig = coderAcademyConfig; } }
創(chuàng)建一個服務自動裝配類。
@Configuration @AutoConfigureAfter({CoderAcademyPropertiesAutoConfig.class}) @ConditionalOnBean({CoderAcademyConfig.class}) public class CoderAcademyAutoConfig { @Bean @ConditionalOnMissingBean public CoderAcademyService coderAcademyService(CoderAcademyConfig coderAcademyConfig){ return new CoderAcademyService(coderAcademyConfig); } }
然后在META-INF/spring.factories
下中使用EnableAutoConfiguration
指定自動配置類。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.springboot.starter.coderacademy.config.CoderAcademyAutoConfig,com.springboot.starter.coderacademy.config.CoderAcademyPropertiesAutoConfig
這時就可以把這個Starter打包推到私服,就可以使用了。
總結
自定義Spring Boot Starter的原理是在應用啟動時,SpringBoot掃描含有spring.factories的jar包,加載其中的org.springframework.boot.autoconfigure.EnableAutoConfiguration條目。引入自定義starter后,相應的自動配置類會被檢測并加載到Spring容器執(zhí)行。通過條件注解等機制,可根據用戶提供的配置信息或其他Bean的存在動態(tài)配置和初始化Bean,實現功能的自動化裝配。自定義starter體現了SpringBoot模塊化和可擴展性,簡化了依賴管理和配置,使開發(fā)者能迅速構建具有特定功能的應用。
以上就是詳解SpringBoot如何創(chuàng)建自定義Starter的詳細內容,更多關于SpringBoot自定義Starter的資料請關注腳本之家其它相關文章!
相關文章
基于HTML5+js+Java實現單文件文件上傳到服務器功能
應公司要求,在HTML5頁面上實現上傳文件到服務器功能,對于我這樣的菜鳥,真是把我難住了,最后還是請教大神搞定的,下面小編把例子分享到腳本之家平臺,供大家參考2017-08-08SpringBoot 2.0 整合sharding-jdbc中間件實現數據分庫分表
這篇文章主要介紹了SpringBoot 2.0 整合sharding-jdbc中間件,實現數據分庫分表,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值 ,需要的朋友可以參考下2019-06-06java如何防止表單重復提交的注解@RepeatSubmit
@RepeatSubmit是一個自定義注解,用于防止表單重復提交,它通過AOP和攔截器模式實現,結合了線程安全和分布式環(huán)境的考慮,注解參數包括interval(間隔時間)和message(提示信息),使用時需要注意并發(fā)處理、用戶體驗、性能和安全性等方面,失效原因是多方面的2024-11-11kafka 重新分配partition和調整replica的數量實現
當需要提升Kafka集群的性能和負載均衡時,可通過kafka-reassign-partitions.sh命令手動重新分配Partition,增加節(jié)點后,可以將Topic的Partition的Leader節(jié)點均勻分布,以提高寫入和消費速度,感興趣的可以了解一下2022-03-03springmvc+shiro+maven 實現登錄認證與權限授權管理
Shiro 是一個 Apache 下的一開源項目項目,旨在簡化身份驗證和授權,下面通過實例代碼給大家分享springmvc+shiro+maven 實現登錄認證與權限授權管理,感興趣的朋友一起看看吧2017-09-09