如何封装独立 SpringBoot Starter

前言

前面我们实现了限流 + 幂等 + Sentinel+Nacos 整套防护能力,如果每个微服务都复制切面、注解、工具类、配置,会出现大量重复代码,维护极其麻烦。

SpringBoot Starter 核心作用:把通用组件抽离成独立 jar 包,业务项目仅引入一行依赖即可自动装配所有功能,零配置侵入

本文手把手完整教学:从零封装自定义 starter,分「命名规范、工程分层、自动装配、配置绑定、业务接入、踩坑总结」全流程,以上文限流幂等安全框架为实战案例。

一、Starter 两种分类 & 命名规范

SpringBoot 官方约定两种 starter,规范必须遵守,否则辨识度低:

  1. 官方 Starter

    命名格式:

    spring-boot-starter-xxx
    

    例:spring-boot-starter-web、spring-boot-starter-data-redis

  2. 自定义业务 / 第三方 Starter(我们用这种)

    命名格式:

    xxx-spring-boot-starter
    

    例:security-spring-boot-starter、mybatis-plus-spring-boot-starter

模块拆分标准(二分法,标准企业结构)

成熟项目建议拆两个模块,职责分离:

  1. xxx-spring-boot-autoconfigure

    :自动装配核心模块

    存放配置类、切面、工具、注解、属性绑定,所有业务逻辑代码

  2. xxx-spring-boot-starter

    :空壳依赖聚合模块

    不写任何 Java 代码,仅 pom 引入 autoconfigure,方便业务项目引入依赖

简易方案(个人小项目):合并为单个 starter 模块,autoconfigure 代码直接放 starter 内,适合简单组件。本文演示简易单模块方案,上手更快。

二、整体工程目录结构(安全防护 starter 示例)

security-spring-boot-starter
├── pom.xml  # starter聚合依赖
└── src
    └── main
        ├── java/com/security/starter
        │   ├── anno          # 自定义注解 @Idempotent
        │   ├── aop           # 幂等切面 IdempotentAspect
        │   ├── config        # 自动装配配置类
        │   │   ├── SecurityAutoConfiguration.java  # 总装配入口
        │   │   └── SentinelNacosAutoConfig.java   # Sentinel nacos持久化配置
        │   ├── core          # 工具类:IdempotentUtil、Result统一返回
        │   ├── prop          # 配置属性绑定类 SecurityProperties
        │   └── exception     # 全局统一异常处理器
        └── resources
            └── META-INF
                └── spring.factories  # SpringBoot自动装配核心文件

三、分步完整编码实现

3.1 父工程版本统一(可选,多模块管理)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.security</groupId>
    <artifactId>security-parent</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <properties>
        <spring.boot.version>2.7.15</spring.boot.version>
        <spring.cloud.alibaba.version>2022.0.0.0</spring.cloud.alibaba.version>
        <sentinel.version>1.8.6</sentinel.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <!-- SpringBoot 父依赖统一管理 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- SpringCloud Alibaba 统一版本 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

3.2 starter 模块 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <parent>
        <groupId>com.security</groupId>
        <artifactId>security-parent</artifactId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>security-spring-boot-starter</artifactId>
    <version>1.0.0</version>
    <name>限流幂等安全框架starter</name>

    <dependencies>
        <!-- Spring Web 基础依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- AOP切面 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!-- Nacos配置中心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!-- Sentinel核心 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!-- Sentinel Nacos持久化数据源 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <!-- fastjson序列化解析sentinel规则 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
            <version>2.0.32</version>
        </dependency>
        <!-- 配置元数据,yml自动提示 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

3.3 配置属性绑定类 SecurityProperties

作用:业务项目 yml 中自定义配置,绑定到实体,控制开关、前缀、超时时间等参数

package com.security.starter.prop;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 配置绑定前缀:security.framework
 */
@ConfigurationProperties(prefix = "security.framework")
public class SecurityProperties {
    // 是否开启整套防护框架,默认开启
    private boolean enable = true;
    // 幂等token redis key前缀
    private String idempotentPrefix = "idempotent:token:";
    // Nacos存储sentinel规则分组
    private String nacosGroup = "SENTINEL_GROUP";
    // nacos dataId前缀
    private String dataIdPrefix = "sentinel-rule-";

    // getter & setter
    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    public String getIdempotentPrefix() {
        return idempotentPrefix;
    }

    public void setIdempotentPrefix(String idempotentPrefix) {
        this.idempotentPrefix = idempotentPrefix;
    }

    public String getNacosGroup() {
        return nacosGroup;
    }

    public void setNacosGroup(String nacosGroup) {
        this.nacosGroup = nacosGroup;
    }

    public String getDataIdPrefix() {
        return dataIdPrefix;
    }

    public void setDataIdPrefix(String dataIdPrefix) {
        this.dataIdPrefix = dataIdPrefix;
    }
}

3.4 自动装配总入口 SecurityAutoConfiguration

核心:条件注解控制组件是否注入,导入子配置类,注册 Bean

package com.security.starter.config;

import com.security.starter.aop.IdempotentAspect;
import com.security.starter.core.IdempotentUtil;
import com.security.starter.prop.SecurityProperties;
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;
import org.springframework.context.annotation.Import;

/**
 * starter自动装配主类
 */
@Configuration
// 开启配置属性绑定
@EnableConfigurationProperties(SecurityProperties.class)
// 条件:配置security.framework.enable=true才加载,不配置默认true
@ConditionalOnProperty(
        prefix = "security.framework",
        name = "enable",
        havingValue = "true",
        matchIfMissing = true
)
// 导入sentinel nacos子配置
@Import(SentinelNacosAutoConfig.class)
public class SecurityAutoConfiguration {

    /** 注入幂等工具类 */
    @Bean
    public IdempotentUtil idempotentUtil() {
        return new IdempotentUtil();
    }

    /** 注入幂等AOP切面 */
    @Bean
    public IdempotentAspect idempotentAspect() {
        return new IdempotentAspect();
    }
}

3.5 子配置:Sentinel Nacos 规则持久化配置

package com.security.starter.config;

import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.TypeReference;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.security.starter.prop.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

@Configuration
public class SentinelNacosAutoConfig {

    @Resource
    private NacosConfigManager nacosConfigManager;

    @Resource
    private SecurityProperties securityProperties;

    @PostConstruct
    public void loadFlowRule() {
        String appName = System.getProperty("spring.application.name");
        String dataId = securityProperties.getDataIdPrefix() + appName;
        String group = securityProperties.getNacosGroup();

        // 构建nacos数据源,监听流控规则变化
        ReadableDataSource<String, List<FlowRule>> flowDataSource = new NacosDataSource<>(
                nacosConfigManager.getNacosConfigService(),
                group,
                dataId,
                source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {})
        );
        // 注册规则管理器,动态监听更新
        FlowRuleManager.register2Property(flowDataSource.getProperty());
    }
}

3.6 核心业务代码(注解、切面、工具、返回体直接放入 starter)

  1. anno/Idempotent.java 幂等注解
  2. aop/IdempotentAspect.java 幂等校验切面
  3. core/IdempotentUtil.java Redis Lua 原子工具类
  4. core/Result.java 全局统一返回体
  5. exception/GlobalExceptionHandler.java 全局异常处理器

3.7 关键文件 spring.factories(自动装配核心)

路径:resources/META-INF/spring.factories

作用:SpringBoot 项目启动时,SPI 机制自动读取该文件,加载我们的自动装配类,不需要业务项目加任何 @Enable 注解

factories

# 自动装配配置类
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.security.starter.config.SecurityAutoConfiguration

3.8 可选:配置元数据(yml 提示)

resources/META-INF 新建 spring-configuration-metadata.json,idea 写 yml 时自动提示配置项,优化开发体验,非必需。

四、打包本地安装 & 推送到私服

4.1 本地 Maven 打包安装(本地测试)

在 starter 根目录执行 maven 命令:

mvn clean install -Dmaven.test.skip=true

执行完成后,jar 包存入本地 maven 仓库,业务项目可直接依赖。

4.2 推送私有 Nexus 私服(多团队共享)

pom 增加 distributionManagement 私服地址,执行 mvn deploy 推送,所有微服务统一拉取。

五、业务微服务如何接入 starter

5.1 引入一行依赖

<dependency>
    <groupId>com.security</groupId>
    <artifactId>security-spring-boot-starter</artifactId>
    <version>1.0.0</version>
</dependency>

5.2 application.yml 最简配置

spring:
  application:
    name: order-service
  redis:
    host: 127.0.0.1
    port: 6379
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080

# 自定义starter配置(全部有默认值,可省略)
security:
  framework:
    enable: true
    nacos-group: SENTINEL_GROUP

5.3 Controller 直接使用,无需任何额外配置

@RestController
@RequestMapping("/api/order")
public class OrderController {
    @Resource
    private IdempotentUtil idempotentUtil;

    @GetMapping("/getToken")
    public Result<String> getToken(){
        return Result.success(idempotentUtil.generateToken(600));
    }

    @PostMapping("/submit")
    @SentinelResource(value = "submitOrder", blockHandler = "blockHandler")
    @Idempotent(message = "请勿重复提交订单")
    public Result<String> submitOrder(){
        return Result.success("下单成功");
    }

    public Result<String> blockHandler(BlockException e){
        return Result.fail("访问过于频繁,请稍后重试");
    }
}

六、核心注解详解(starter 条件装配关键)

  1. @Configuration
    

    标记当前类为配置类,Spring 启动扫描注册 Bean

  2. @EnableConfigurationProperties
    

    开启配置绑定,将 yml 配置注入 Properties 实体

  3. @ConditionalOnProperty
    

    根据 yml 配置开关控制整套组件是否生效

  4. @ConditionalOnClass
    

    判断 class 存在才注入 Bean,例如存在 RedisTemplate 才装配 Redis 工具

  5. @ConditionalOnMissingBean
    

    业务项目自定义 Bean 时,覆盖 starter 默认 Bean,提供扩展能力

  6. @Import
    

    导入其他配置类,拆分复杂配置,解耦代码

七、企业级扩展优化方案

  1. 支持用户自定义覆盖 Bean

    工具类、切面使用

    @ConditionalOnMissingBean
    

    ,业务项目可自定义实现替换 starter 默认逻辑。

  2. 多环境配置隔离

    Properties 增加环境标识,Nacos 分组区分 dev/test/prod 规则。

  3. 扩展 starter 自动提示

    配置 spring-configuration-processor 依赖,自动生成配置提示文件。

  4. 拆分多规则持久化

    在 Sentinel 配置中扩展熔断、热点参数、系统规则 Nacos 数据源。

  5. 增加日志埋点

    AOP 切面记录限流、重复提交拦截日志,便于线上排查。

  6. 适配 Gateway 网关

    区分 web 环境和 reactive 响应式 web,增加

    @ConditionalOnWebApplication
    

    适配网关。

八、常见踩坑问题总结

1. starter 装配不生效,切面 / 工具类未注入

  • 检查 resources/META-INF/spring.factories 文件路径、类全限定名是否写错;
  • maven 打包时是否跳过资源文件,build 节点配置 resource 拷贝;
  • 确认配置开关 security.framework.enable=true

2. yml 配置不生效,属性无法注入

  • 缺少 @EnableConfigurationProperties 注解;
  • 配置前缀与 Properties 类注解不一致;
  • 未引入 configuration-processor 依赖,idea 无提示不影响运行。

3. Nacos Sentinel 规则拉取不到

  • nacos dataId、group 与配置类完全匹配;
  • 缺少 sentinel-datasource-nacos 依赖;
  • 服务必须配置 spring.application.name。

4. AOP 切面执行顺序错乱

@SentinelResource 是拦截器,优先级高于 SpringAOP,天然先限流后幂等,无需额外调整。

5. 打包后本地项目无法引用

执行 install 命令,跳过测试;groupId、artifactId 和依赖引入保持一致。

九、总结

  1. SpringBoot Starter 核心原理:SPI 机制 + 条件注解自动装配,实现组件开箱即用;
  2. 标准封装流程:创建模块→编写业务组件→属性绑定配置类→编写自动装配入口→配置 spring.factories→打包;
  3. 优势:消除多项目重复代码、统一技术规范、业务项目极低接入成本、统一升级维护;
  4. 本文案例可直接复用,基于前面限流幂等 Sentinel 全套代码,一键封装成企业通用安全防护 Starter。

更多推荐