SpringBoot Starter自定義之創(chuàng)建可復(fù)用的自動(dòng)配置模塊方式
引言
Spring Boot Starter是Spring Boot生態(tài)系統(tǒng)的核心組成部分,它極大地簡(jiǎn)化了項(xiàng)目的依賴管理和配置過(guò)程。通過(guò)Starter機(jī)制,開發(fā)者只需引入相應(yīng)的依賴,Spring Boot就能自動(dòng)完成復(fù)雜的配置工作。對(duì)于企業(yè)級(jí)應(yīng)用開發(fā),我們經(jīng)常需要在多個(gè)項(xiàng)目中復(fù)用某些通用功能,這時(shí)創(chuàng)建自定義Starter就顯得尤為重要。
一、自定義Starter基礎(chǔ)知識(shí)
Spring Boot Starter本質(zhì)上是一組依賴項(xiàng)的集合,同時(shí)結(jié)合自動(dòng)配置類,為特定功能提供開箱即用的體驗(yàn)。自定義Starter的核心目標(biāo)是將可復(fù)用的功能模塊化,讓其他項(xiàng)目能夠通過(guò)簡(jiǎn)單的依賴引入來(lái)使用這些功能。
一個(gè)標(biāo)準(zhǔn)的Spring Boot Starter通常由兩個(gè)主要組件構(gòu)成:自動(dòng)配置模塊和Starter模塊。自動(dòng)配置模塊包含功能的具體實(shí)現(xiàn)和配置類,而Starter模塊則作為一個(gè)空殼,僅依賴于自動(dòng)配置模塊和其他必要的依賴。這種分離設(shè)計(jì)使得功能實(shí)現(xiàn)與依賴管理解耦,提高了模塊的靈活性。
以下是自定義Starter的基本命名規(guī)范:
// 對(duì)于官方Starter,命名格式為: spring-boot-starter-{功能名} // 對(duì)于非官方Starter,命名格式為: {項(xiàng)目名}-spring-boot-starter
命名規(guī)范的遵循有助于區(qū)分官方與第三方Starter,避免潛在的命名沖突。
二、創(chuàng)建自動(dòng)配置模塊
自動(dòng)配置模塊是Starter的核心,它包含了功能的具體實(shí)現(xiàn)和自動(dòng)配置類。
我們以創(chuàng)建一個(gè)簡(jiǎn)單的數(shù)據(jù)加密Starter為例,展示自動(dòng)配置模塊的創(chuàng)建過(guò)程。
2.1 項(xiàng)目結(jié)構(gòu)搭建
首先創(chuàng)建一個(gè)Maven項(xiàng)目,命名為encryption-spring-boot-autoconfigure
,作為自動(dòng)配置模塊。
項(xiàng)目結(jié)構(gòu)如下:
encryption-spring-boot-autoconfigure/ ├── src/ │ ├── main/ │ │ ├── java/ │ │ │ └── com/ │ │ │ └── example/ │ │ │ └── encryption/ │ │ │ ├── autoconfigure/ │ │ │ │ └── EncryptionAutoConfiguration.java │ │ │ ├── properties/ │ │ │ │ └── EncryptionProperties.java │ │ │ └── service/ │ │ │ ├── EncryptionService.java │ │ │ └── impl/ │ │ │ └── AESEncryptionServiceImpl.java │ │ └── resources/ │ │ └── META-INF/ │ │ └── spring.factories └── pom.xml
2.2 配置屬性類
創(chuàng)建配置屬性類,用于存儲(chǔ)和管理加密服務(wù)的相關(guān)配置:
package com.example.encryption.properties; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 加密服務(wù)配置屬性類 * 通過(guò)@ConfigurationProperties注解綁定配置文件中的屬性 */ @ConfigurationProperties(prefix = "encryption") public class EncryptionProperties { /** * 加密算法,默認(rèn)為AES */ private String algorithm = "AES"; /** * 加密密鑰 */ private String key = "defaultKey123456"; /** * 是否啟用加密服務(wù) */ private boolean enabled = true; // Getter和Setter方法 public String getAlgorithm() { return algorithm; } public void setAlgorithm(String algorithm) { this.algorithm = algorithm; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } }
2.3 服務(wù)接口及實(shí)現(xiàn)
定義加密服務(wù)接口及其實(shí)現(xiàn):
package com.example.encryption.service; /** * 加密服務(wù)接口 * 定義加密和解密的基本操作 */ public interface EncryptionService { /** * 加密字符串 * * @param content 待加密內(nèi)容 * @return 加密后的內(nèi)容 */ String encrypt(String content); /** * 解密字符串 * * @param encryptedContent 已加密內(nèi)容 * @return 解密后的原文 */ String decrypt(String encryptedContent); }
AES加密實(shí)現(xiàn)類:
package com.example.encryption.service.impl; import com.example.encryption.properties.EncryptionProperties; import com.example.encryption.service.EncryptionService; import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.util.Base64; /** * AES加密服務(wù)實(shí)現(xiàn) * 提供基于AES算法的加密和解密功能 */ public class AESEncryptionServiceImpl implements EncryptionService { private final EncryptionProperties properties; public AESEncryptionServiceImpl(EncryptionProperties properties) { this.properties = properties; } @Override public String encrypt(String content) { try { // 創(chuàng)建密鑰規(guī)范 SecretKeySpec keySpec = new SecretKeySpec( properties.getKey().getBytes(StandardCharsets.UTF_8), properties.getAlgorithm() ); // 獲取Cipher實(shí)例 Cipher cipher = Cipher.getInstance(properties.getAlgorithm()); // 初始化為加密模式 cipher.init(Cipher.ENCRYPT_MODE, keySpec); // 執(zhí)行加密 byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)); // 返回Base64編碼后的加密結(jié)果 return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("加密失敗", e); } } @Override public String decrypt(String encryptedContent) { try { // 創(chuàng)建密鑰規(guī)范 SecretKeySpec keySpec = new SecretKeySpec( properties.getKey().getBytes(StandardCharsets.UTF_8), properties.getAlgorithm() ); // 獲取Cipher實(shí)例 Cipher cipher = Cipher.getInstance(properties.getAlgorithm()); // 初始化為解密模式 cipher.init(Cipher.DECRYPT_MODE, keySpec); // 執(zhí)行解密 byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedContent)); // 返回解密后的原文 return new String(original, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("解密失敗", e); } } }
2.4 自動(dòng)配置類
創(chuàng)建自動(dòng)配置類,根據(jù)條件自動(dòng)裝配加密服務(wù):
package com.example.encryption.autoconfigure; import com.example.encryption.properties.EncryptionProperties; import com.example.encryption.service.EncryptionService; import com.example.encryption.service.impl.AESEncryptionServiceImpl; 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; /** * 加密服務(wù)自動(dòng)配置類 * 負(fù)責(zé)根據(jù)條件自動(dòng)裝配加密服務(wù) */ @Configuration @ConditionalOnClass(EncryptionService.class) @EnableConfigurationProperties(EncryptionProperties.class) @ConditionalOnProperty(prefix = "encryption", name = "enabled", havingValue = "true", matchIfMissing = true) public class EncryptionAutoConfiguration { /** * 注冊(cè)加密服務(wù)Bean * 當(dāng)容器中不存在EncryptionService類型的Bean時(shí),創(chuàng)建默認(rèn)實(shí)現(xiàn) */ @Bean @ConditionalOnMissingBean public EncryptionService encryptionService(EncryptionProperties properties) { return new AESEncryptionServiceImpl(properties); } }
2.5 spring.factories文件
在META-INF
目錄下創(chuàng)建spring.factories
文件,指定自動(dòng)配置類:
# 自動(dòng)配置類 org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.example.encryption.autoconfigure.EncryptionAutoConfiguration
2.6 Maven依賴配置
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.example</groupId> <artifactId>encryption-spring-boot-autoconfigure</artifactId> <version>1.0.0</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <spring-boot.version>2.7.0</spring-boot.version> </properties> <dependencies> <!-- Spring Boot AutoConfigure --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> <version>${spring-boot.version}</version> </dependency> <!-- 用于生成配置元數(shù)據(jù) --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>${spring-boot.version}</version> <optional>true</optional> </dependency> </dependencies> </project>
三、創(chuàng)建Starter模塊
Starter模塊是一個(gè)空殼模塊,它依賴于自動(dòng)配置模塊和其他必要的依賴,向使用者提供一站式的依賴引入體驗(yàn)。
3.1 項(xiàng)目結(jié)構(gòu)
創(chuàng)建一個(gè)Maven項(xiàng)目,命名為encryption-spring-boot-starter
,作為Starter模塊:
encryption-spring-boot-starter/ └── pom.xml
3.2 Maven依賴配置
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.example</groupId> <artifactId>encryption-spring-boot-starter</artifactId> <version>1.0.0</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!-- 依賴自動(dòng)配置模塊 --> <dependency> <groupId>com.example</groupId> <artifactId>encryption-spring-boot-autoconfigure</artifactId> <version>1.0.0</version> </dependency> <!-- 依賴其他必要的庫(kù),根據(jù)功能需求添加 --> </dependencies> </project>
四、使用自定義Starter
創(chuàng)建完成后,我們可以在其他項(xiàng)目中使用這個(gè)自定義的Starter。
4.1 添加依賴
在項(xiàng)目的pom.xml
中添加依賴:
<dependency> <groupId>com.example</groupId> <artifactId>encryption-spring-boot-starter</artifactId> <version>1.0.0</version> </dependency>
4.2 配置屬性
在application.properties
或application.yml
中配置加密服務(wù)屬性:
# 開啟加密服務(wù) encryption.enabled=true # 設(shè)置加密算法 encryption.algorithm=AES # 設(shè)置加密密鑰 encryption.key=mySecretKey12345
4.3 使用示例
在業(yè)務(wù)代碼中注入并使用加密服務(wù):
package com.example.demo; import com.example.encryption.service.EncryptionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; /** * 加密服務(wù)演示控制器 * 展示如何在業(yè)務(wù)代碼中使用自定義Starter提供的功能 */ @RestController public class EncryptionController { private final EncryptionService encryptionService; @Autowired public EncryptionController(EncryptionService encryptionService) { this.encryptionService = encryptionService; } @GetMapping("/encrypt") public String encrypt(@RequestParam String content) { return encryptionService.encrypt(content); } @GetMapping("/decrypt") public String decrypt(@RequestParam String content) { return encryptionService.decrypt(content); } }
五、Starter高級(jí)特性
5.1 條件化配置
Spring Boot提供了豐富的條件注解,用于控制Bean的裝配條件,使自定義Starter更加靈活:
// 當(dāng)類路徑下存在指定類時(shí)生效 @ConditionalOnClass(name = "com.example.SomeClass") // 當(dāng)Bean不存在時(shí)生效 @ConditionalOnMissingBean // 當(dāng)配置屬性滿足條件時(shí)生效 @ConditionalOnProperty(prefix = "feature", name = "enabled", havingValue = "true") // 當(dāng)環(huán)境為指定profile時(shí)生效 @ConditionalOnProfile("dev") // 當(dāng)Web應(yīng)用為Servlet類型時(shí)生效 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
5.2 自動(dòng)配置順序控制
在復(fù)雜場(chǎng)景下,可能需要控制多個(gè)自動(dòng)配置類的執(zhí)行順序,可以使用@AutoConfigureBefore
和@AutoConfigureAfter
注解:
// 在指定自動(dòng)配置類之前執(zhí)行 @AutoConfigureBefore(OtherAutoConfiguration.class) // 在指定自動(dòng)配置類之后執(zhí)行 @AutoConfigureAfter(OtherAutoConfiguration.class) // 示例代碼 @Configuration @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class EncryptionAutoConfiguration { // 配置代碼 }
5.3 配置元數(shù)據(jù)
為了提供更好的IDE支持,可以創(chuàng)建配置元數(shù)據(jù)文件:
{ "groups": [ { "name": "encryption", "type": "com.example.encryption.properties.EncryptionProperties", "sourceType": "com.example.encryption.properties.EncryptionProperties" } ], "properties": [ { "name": "encryption.enabled", "type": "java.lang.Boolean", "description": "是否啟用加密服務(wù)", "sourceType": "com.example.encryption.properties.EncryptionProperties", "defaultValue": true }, { "name": "encryption.algorithm", "type": "java.lang.String", "description": "加密算法", "sourceType": "com.example.encryption.properties.EncryptionProperties", "defaultValue": "AES" }, { "name": "encryption.key", "type": "java.lang.String", "description": "加密密鑰", "sourceType": "com.example.encryption.properties.EncryptionProperties", "defaultValue": "defaultKey123456" } ], "hints": [ { "name": "encryption.algorithm", "values": [ { "value": "AES", "description": "AES加密算法" }, { "value": "DES", "description": "DES加密算法" } ] } ] }
配置元數(shù)據(jù)文件應(yīng)放在META-INF/spring-configuration-metadata.json
路徑下,通常由spring-boot-configuration-processor
自動(dòng)生成。
總結(jié)
Spring Boot Starter是一種強(qiáng)大的自動(dòng)配置機(jī)制,通過(guò)自定義Starter,我們可以將業(yè)務(wù)中的通用功能模塊化,實(shí)現(xiàn)代碼的高度復(fù)用。自定義Starter的核心在于合理設(shè)計(jì)自動(dòng)配置類和配置屬性類,讓用戶能夠通過(guò)簡(jiǎn)單的配置來(lái)定制功能行為。
在創(chuàng)建過(guò)程中,我們需要遵循Spring Boot的命名規(guī)范和最佳實(shí)踐,將自動(dòng)配置模塊與Starter模塊分離,提高靈活性。通過(guò)條件化配置和自動(dòng)配置順序控制,可以讓Starter在復(fù)雜場(chǎng)景中也能穩(wěn)定工作。
對(duì)于企業(yè)級(jí)應(yīng)用開發(fā),自定義Starter是提升團(tuán)隊(duì)效率的關(guān)鍵工具,它不僅能簡(jiǎn)化項(xiàng)目配置,還能確保各個(gè)項(xiàng)目遵循統(tǒng)一的最佳實(shí)踐,降低維護(hù)成本。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Java集合中的基本數(shù)據(jù)結(jié)構(gòu)
總有小伙伴讓我總結(jié)一下Java集合中的基本數(shù)據(jù)結(jié)構(gòu)的相關(guān)知識(shí),今天特地整理了本篇文章,文中有非常詳細(xì)的介紹,需要的朋友可以參考下2021-06-06IDEA如何加載resources文件夾下文件相對(duì)路徑
這篇文章主要介紹了IDEA如何加載resources文件夾下文件相對(duì)路徑問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12Java使用DFA算法實(shí)現(xiàn)過(guò)濾多家公司自定義敏感字功能詳解
這篇文章主要介紹了Java使用DFA算法實(shí)現(xiàn)過(guò)濾多家公司自定義敏感字功能,結(jié)合實(shí)例形式分析了DFA算法的實(shí)現(xiàn)原理及過(guò)濾敏感字的相關(guān)操作技巧,需要的朋友可以參考下2017-08-08springboot實(shí)現(xiàn)全局異常捕獲的使用示例
任何系統(tǒng),我們不會(huì)傻傻的在每一個(gè)地方進(jìn)行異常捕獲和處理,整個(gè)系統(tǒng)一般我們會(huì)在一個(gè)的地方統(tǒng)一進(jìn)行異常處理,本文主要介紹了springboot實(shí)現(xiàn)全局異常捕獲的使用示例,感興趣的可以了解一下2023-11-11Spring Cloud Alibaba Nacos 入門詳解
這篇文章主要介紹了Spring Cloud Alibaba Nacos入門詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2019-03-03MybatisPlusException:Failed?to?process,Error?SQL異常報(bào)錯(cuò)的解決辦法
這篇文章主要給大家介紹了關(guān)于MybatisPlusException:Failed?to?process,Error?SQL異常報(bào)錯(cuò)的解決辦法,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-03-03SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端)
這篇文章主要介紹了SpringBoot+MyBatisPlus+Vue 前后端分離項(xiàng)目快速搭建過(guò)程(后端),快速生成后端代碼、封裝結(jié)果集、增刪改查、模糊查找,畢設(shè)基礎(chǔ)框架,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-05-05使用ScheduledThreadPoolExecutor踩過(guò)最痛的坑
這篇文章主要介紹了使用ScheduledThreadPoolExecutor踩過(guò)最痛的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08Java實(shí)現(xiàn)俄羅斯方塊游戲簡(jiǎn)單版
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)俄羅斯方塊游戲簡(jiǎn)單版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01