SpringBoot Starter自定义之创建可复用的自动配置模块方式
作者:程序媛学姐
引言
Spring Boot Starter是Spring Boot生态系统的核心组成部分,它极大地简化了项目的依赖管理和配置过程。通过Starter机制,开发者只需引入相应的依赖,Spring Boot就能自动完成复杂的配置工作。对于企业级应用开发,我们经常需要在多个项目中复用某些通用功能,这时创建自定义Starter就显得尤为重要。
一、自定义Starter基础知识
Spring Boot Starter本质上是一组依赖项的集合,同时结合自动配置类,为特定功能提供开箱即用的体验。自定义Starter的核心目标是将可复用的功能模块化,让其他项目能够通过简单的依赖引入来使用这些功能。
一个标准的Spring Boot Starter通常由两个主要组件构成:自动配置模块和Starter模块。自动配置模块包含功能的具体实现和配置类,而Starter模块则作为一个空壳,仅依赖于自动配置模块和其他必要的依赖。这种分离设计使得功能实现与依赖管理解耦,提高了模块的灵活性。
以下是自定义Starter的基本命名规范:
// 对于官方Starter,命名格式为: spring-boot-starter-{功能名} // 对于非官方Starter,命名格式为: {项目名}-spring-boot-starter
命名规范的遵循有助于区分官方与第三方Starter,避免潜在的命名冲突。
二、创建自动配置模块
自动配置模块是Starter的核心,它包含了功能的具体实现和自动配置类。
我们以创建一个简单的数据加密Starter为例,展示自动配置模块的创建过程。
2.1 项目结构搭建
首先创建一个Maven项目,命名为encryption-spring-boot-autoconfigure
,作为自动配置模块。
项目结构如下:
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 配置属性类
创建配置属性类,用于存储和管理加密服务的相关配置:
package com.example.encryption.properties; import org.springframework.boot.context.properties.ConfigurationProperties; /** * 加密服务配置属性类 * 通过@ConfigurationProperties注解绑定配置文件中的属性 */ @ConfigurationProperties(prefix = "encryption") public class EncryptionProperties { /** * 加密算法,默认为AES */ private String algorithm = "AES"; /** * 加密密钥 */ private String key = "defaultKey123456"; /** * 是否启用加密服务 */ 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 服务接口及实现
定义加密服务接口及其实现:
package com.example.encryption.service; /** * 加密服务接口 * 定义加密和解密的基本操作 */ public interface EncryptionService { /** * 加密字符串 * * @param content 待加密内容 * @return 加密后的内容 */ String encrypt(String content); /** * 解密字符串 * * @param encryptedContent 已加密内容 * @return 解密后的原文 */ String decrypt(String encryptedContent); }
AES加密实现类:
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加密服务实现 * 提供基于AES算法的加密和解密功能 */ public class AESEncryptionServiceImpl implements EncryptionService { private final EncryptionProperties properties; public AESEncryptionServiceImpl(EncryptionProperties properties) { this.properties = properties; } @Override public String encrypt(String content) { try { // 创建密钥规范 SecretKeySpec keySpec = new SecretKeySpec( properties.getKey().getBytes(StandardCharsets.UTF_8), properties.getAlgorithm() ); // 获取Cipher实例 Cipher cipher = Cipher.getInstance(properties.getAlgorithm()); // 初始化为加密模式 cipher.init(Cipher.ENCRYPT_MODE, keySpec); // 执行加密 byte[] encrypted = cipher.doFinal(content.getBytes(StandardCharsets.UTF_8)); // 返回Base64编码后的加密结果 return Base64.getEncoder().encodeToString(encrypted); } catch (Exception e) { throw new RuntimeException("加密失败", e); } } @Override public String decrypt(String encryptedContent) { try { // 创建密钥规范 SecretKeySpec keySpec = new SecretKeySpec( properties.getKey().getBytes(StandardCharsets.UTF_8), properties.getAlgorithm() ); // 获取Cipher实例 Cipher cipher = Cipher.getInstance(properties.getAlgorithm()); // 初始化为解密模式 cipher.init(Cipher.DECRYPT_MODE, keySpec); // 执行解密 byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedContent)); // 返回解密后的原文 return new String(original, StandardCharsets.UTF_8); } catch (Exception e) { throw new RuntimeException("解密失败", e); } } }
2.4 自动配置类
创建自动配置类,根据条件自动装配加密服务:
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; /** * 加密服务自动配置类 * 负责根据条件自动装配加密服务 */ @Configuration @ConditionalOnClass(EncryptionService.class) @EnableConfigurationProperties(EncryptionProperties.class) @ConditionalOnProperty(prefix = "encryption", name = "enabled", havingValue = "true", matchIfMissing = true) public class EncryptionAutoConfiguration { /** * 注册加密服务Bean * 当容器中不存在EncryptionService类型的Bean时,创建默认实现 */ @Bean @ConditionalOnMissingBean public EncryptionService encryptionService(EncryptionProperties properties) { return new AESEncryptionServiceImpl(properties); } }
2.5 spring.factories文件
在META-INF
目录下创建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> <!-- 用于生成配置元数据 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <version>${spring-boot.version}</version> <optional>true</optional> </dependency> </dependencies> </project>
三、创建Starter模块
Starter模块是一个空壳模块,它依赖于自动配置模块和其他必要的依赖,向使用者提供一站式的依赖引入体验。
3.1 项目结构
创建一个Maven项目,命名为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> <!-- 依赖其他必要的库,根据功能需求添加 --> </dependencies> </project>
四、使用自定义Starter
创建完成后,我们可以在其他项目中使用这个自定义的Starter。
4.1 添加依赖
在项目的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
中配置加密服务属性:
# 开启加密服务 encryption.enabled=true # 设置加密算法 encryption.algorithm=AES # 设置加密密钥 encryption.key=mySecretKey12345
4.3 使用示例
在业务代码中注入并使用加密服务:
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; /** * 加密服务演示控制器 * 展示如何在业务代码中使用自定义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更加灵活:
// 当类路径下存在指定类时生效 @ConditionalOnClass(name = "com.example.SomeClass") // 当Bean不存在时生效 @ConditionalOnMissingBean // 当配置属性满足条件时生效 @ConditionalOnProperty(prefix = "feature", name = "enabled", havingValue = "true") // 当环境为指定profile时生效 @ConditionalOnProfile("dev") // 当Web应用为Servlet类型时生效 @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
5.2 自动配置顺序控制
在复杂场景下,可能需要控制多个自动配置类的执行顺序,可以使用@AutoConfigureBefore
和@AutoConfigureAfter
注解:
// 在指定自动配置类之前执行 @AutoConfigureBefore(OtherAutoConfiguration.class) // 在指定自动配置类之后执行 @AutoConfigureAfter(OtherAutoConfiguration.class) // 示例代码 @Configuration @AutoConfigureAfter(DataSourceAutoConfiguration.class) public class EncryptionAutoConfiguration { // 配置代码 }
5.3 配置元数据
为了提供更好的IDE支持,可以创建配置元数据文件:
{ "groups": [ { "name": "encryption", "type": "com.example.encryption.properties.EncryptionProperties", "sourceType": "com.example.encryption.properties.EncryptionProperties" } ], "properties": [ { "name": "encryption.enabled", "type": "java.lang.Boolean", "description": "是否启用加密服务", "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加密算法" } ] } ] }
配置元数据文件应放在META-INF/spring-configuration-metadata.json
路径下,通常由spring-boot-configuration-processor
自动生成。
总结
Spring Boot Starter是一种强大的自动配置机制,通过自定义Starter,我们可以将业务中的通用功能模块化,实现代码的高度复用。自定义Starter的核心在于合理设计自动配置类和配置属性类,让用户能够通过简单的配置来定制功能行为。
在创建过程中,我们需要遵循Spring Boot的命名规范和最佳实践,将自动配置模块与Starter模块分离,提高灵活性。通过条件化配置和自动配置顺序控制,可以让Starter在复杂场景中也能稳定工作。
对于企业级应用开发,自定义Starter是提升团队效率的关键工具,它不仅能简化项目配置,还能确保各个项目遵循统一的最佳实践,降低维护成本。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。