SpringBoot Starter自定義之創(chuàng)建可復(fù)用的自動配置模塊方式
引言
Spring Boot Starter是Spring Boot生態(tài)系統(tǒng)的核心組成部分,它極大地簡化了項(xiàng)目的依賴管理和配置過程。通過Starter機(jī)制,開發(fā)者只需引入相應(yīng)的依賴,Spring Boot就能自動完成復(fù)雜的配置工作。對于企業(yè)級應(yīng)用開發(fā),我們經(jīng)常需要在多個項(xiàng)目中復(fù)用某些通用功能,這時創(chuàng)建自定義Starter就顯得尤為重要。
一、自定義Starter基礎(chǔ)知識
Spring Boot Starter本質(zhì)上是一組依賴項(xiàng)的集合,同時結(jié)合自動配置類,為特定功能提供開箱即用的體驗(yàn)。自定義Starter的核心目標(biāo)是將可復(fù)用的功能模塊化,讓其他項(xiàng)目能夠通過簡單的依賴引入來使用這些功能。
一個標(biāo)準(zhǔn)的Spring Boot Starter通常由兩個主要組件構(gòu)成:自動配置模塊和Starter模塊。自動配置模塊包含功能的具體實(shí)現(xiàn)和配置類,而Starter模塊則作為一個空殼,僅依賴于自動配置模塊和其他必要的依賴。這種分離設(shè)計(jì)使得功能實(shí)現(xiàn)與依賴管理解耦,提高了模塊的靈活性。
以下是自定義Starter的基本命名規(guī)范:
// 對于官方Starter,命名格式為:
spring-boot-starter-{功能名}
// 對于非官方Starter,命名格式為:
{項(xiàng)目名}-spring-boot-starter命名規(guī)范的遵循有助于區(qū)分官方與第三方Starter,避免潛在的命名沖突。
二、創(chuàng)建自動配置模塊
自動配置模塊是Starter的核心,它包含了功能的具體實(shí)現(xiàn)和自動配置類。
我們以創(chuàng)建一個簡單的數(shù)據(jù)加密Starter為例,展示自動配置模塊的創(chuàng)建過程。
2.1 項(xiàng)目結(jié)構(gòu)搭建
首先創(chuàng)建一個Maven項(xiàng)目,命名為encryption-spring-boot-autoconfigure,作為自動配置模塊。
項(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)建配置屬性類,用于存儲和管理加密服務(wù)的相關(guān)配置:
package com.example.encryption.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* 加密服務(wù)配置屬性類
* 通過@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 自動配置類
創(chuàng)建自動配置類,根據(jù)條件自動裝配加密服務(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ù)自動配置類
* 負(fù)責(zé)根據(jù)條件自動裝配加密服務(wù)
*/
@Configuration
@ConditionalOnClass(EncryptionService.class)
@EnableConfigurationProperties(EncryptionProperties.class)
@ConditionalOnProperty(prefix = "encryption", name = "enabled", havingValue = "true", matchIfMissing = true)
public class EncryptionAutoConfiguration {
/**
* 注冊加密服務(wù)Bean
* 當(dāng)容器中不存在EncryptionService類型的Bean時,創(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文件,指定自動配置類:
# 自動配置類 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模塊是一個空殼模塊,它依賴于自動配置模塊和其他必要的依賴,向使用者提供一站式的依賴引入體驗(yàn)。
3.1 項(xiàng)目結(jié)構(gòu)
創(chuàng)建一個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>
<!-- 依賴自動配置模塊 -->
<dependency>
<groupId>com.example</groupId>
<artifactId>encryption-spring-boot-autoconfigure</artifactId>
<version>1.0.0</version>
</dependency>
<!-- 依賴其他必要的庫,根據(jù)功能需求添加 -->
</dependencies>
</project>四、使用自定義Starter
創(chuàng)建完成后,我們可以在其他項(xiàng)目中使用這個自定義的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高級特性
5.1 條件化配置
Spring Boot提供了豐富的條件注解,用于控制Bean的裝配條件,使自定義Starter更加靈活:
// 當(dāng)類路徑下存在指定類時生效
@ConditionalOnClass(name = "com.example.SomeClass")
// 當(dāng)Bean不存在時生效
@ConditionalOnMissingBean
// 當(dāng)配置屬性滿足條件時生效
@ConditionalOnProperty(prefix = "feature", name = "enabled", havingValue = "true")
// 當(dāng)環(huán)境為指定profile時生效
@ConditionalOnProfile("dev")
// 當(dāng)Web應(yīng)用為Servlet類型時生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)5.2 自動配置順序控制
在復(fù)雜場景下,可能需要控制多個自動配置類的執(zhí)行順序,可以使用@AutoConfigureBefore和@AutoConfigureAfter注解:
// 在指定自動配置類之前執(zhí)行
@AutoConfigureBefore(OtherAutoConfiguration.class)
// 在指定自動配置類之后執(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自動生成。
總結(jié)
Spring Boot Starter是一種強(qiáng)大的自動配置機(jī)制,通過自定義Starter,我們可以將業(yè)務(wù)中的通用功能模塊化,實(shí)現(xiàn)代碼的高度復(fù)用。自定義Starter的核心在于合理設(shè)計(jì)自動配置類和配置屬性類,讓用戶能夠通過簡單的配置來定制功能行為。
在創(chuàng)建過程中,我們需要遵循Spring Boot的命名規(guī)范和最佳實(shí)踐,將自動配置模塊與Starter模塊分離,提高靈活性。通過條件化配置和自動配置順序控制,可以讓Starter在復(fù)雜場景中也能穩(wěn)定工作。
對于企業(yè)級應(yīng)用開發(fā),自定義Starter是提升團(tuán)隊(duì)效率的關(guān)鍵工具,它不僅能簡化項(xiàng)目配置,還能確保各個項(xiàng)目遵循統(tǒng)一的最佳實(shí)踐,降低維護(hù)成本。
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java 文創(chuàng)商城系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+mysql+maven+tomcat實(shí)現(xiàn)一個文創(chuàng)商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11
詳解自動注冊Gateway網(wǎng)關(guān)路由配置
這篇文章主要為大家介紹了自動注冊Gateway網(wǎng)關(guān)路由配置的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
Java實(shí)現(xiàn)高校教務(wù)系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)高校教務(wù)系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-08-08
Java并發(fā)程序刺客之假共享的原理及復(fù)現(xiàn)
前段時間在各種社交平臺“雪糕刺客”這個詞比較火,而在并發(fā)程序中也有一個刺客,那就是假共享。本文將通過示例詳細(xì)講解假共享的原理及復(fù)現(xiàn),需要的可以參考一下2022-08-08
一文告訴你為什么要重寫hashCode()方法和equals()方法
本篇文章帶大家了解一下為什么重寫hashCode()方法和equals()方法,文中有非常詳細(xì)的說明以及代碼示例,對正在學(xué)習(xí)java的小伙伴們很有幫助,需要的朋友可以參考下2021-05-05

