# spring-boot-starter
**Repository Path**: luminion/spring-boot-starter
## Basic Information
- **Project Name**: spring-boot-starter
- **Description**: 开箱即用的spring-boot-starter, 提供JSON序列化/方法限流/字段注解脱敏加解密/Spring-core多类型converter/xss防护/错误日志邮件推送/多个注解驱动等功能
- **Primary Language**: Unknown
- **License**: Apache-2.0
- **Default Branch**: master
- **Homepage**: https://github.com/luminion/spring-boot-starter
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2024-12-24
- **Last Updated**: 2026-07-16
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Velo Spring Boot Starter
[](https://central.sonatype.com/artifact/io.github.luminion/velo-spring-boot3-starter)
[](LICENSE)
[](https://github.com/luminion/spring-boot-starter)
Velo Spring Boot Starter 是一组低侵入的 Spring Boot 自动配置扩展。
项目以 `velo.*` 作为统一配置入口,围绕并发控制、缓存、Jackson、Redis、MyBatis-Plus、Excel、日志、XSS 和 Web MVC 常用增强提供开箱能力。
## 功能特性
- 统一的 `velo.*` 配置模型,集中管理各类自动配置开关
- 提供 `@Idempotent`、`@RateLimit`、`@Lock` 三类并发控制能力
- 支持 Redis / Redisson / Caffeine / JDK 多后端并自动降级
- 提供 Spring Cache + Redis Cache 的统一 TTL 和 key 前缀配置
- 提供 Jackson 日期时间、超大整数、枚举派生字段、字符串转换增强
- 提供 MyBatis-Plus 分页、乐观锁、防全表更新拦截器自动注册
- 提供 RedisTemplate 序列化风格统一能力
- 提供 Excel 扩展 converter 自动注册和 helper 工具类
- 提供注解日志、Controller 请求日志、XSS 清洗和 Web MVC 日期绑定增强
---
## 总览
Velo 默认使用 `velo.mode=OPINIONATED`,目标是引入 starter 后直接获得常用增强能力。
如果你希望 starter 只保留显式注解类能力,尽量不自动改变全局行为,可以切到保守模式:
```yaml
velo:
mode: CONSERVATIVE
```
模式说明:
- `OPINIONATED`:默认模式,开启偏开箱即用的全局增强
- `CONSERVATIVE`:关闭容易自动影响应用行为的默认项,但 `@Idempotent`、`@RateLimit`、`@Lock`、`@InvokeLog`、`@SlowLog` 等显式注解仍可用
- `CONSERVATIVE` 只提供低优先级默认值,业务项目显式配置的属性优先级更高
- 保守模式下重新打开某类能力时,需要显式设置对应的 `enabled` 项,例如 `velo.jackson.enabled=true`
- 启用 `CONSERVATIVE` 后,starter 会在启动日志中输出一条 INFO,列出被默认关闭的能力,便于排查"为什么某全局增强没生效"
配置优先级(从高到低):
| 优先级 | 来源 | 示例 |
| --- | --- | --- |
| 1 最高 | 命令行参数 | `--velo.log.trace.enabled=true` |
| 2 | application.yml / properties | `velo.log.trace.enabled: true` |
| 3 | 环境变量 | `VELO_LOG_TRACE_ENABLED=true` |
| 4 最低 | `velo.mode` 默认值 | `OPINIONATED` / `CONSERVATIVE` 注入的默认值 |
也就是说 `velo.mode` 注入的只是**最低优先级默认值**,业务项目任何显式配置都会覆盖它。
例如保守模式下重新打开 traceId:
```yaml
velo:
mode: CONSERVATIVE
log:
trace:
enabled: true
```
默认会自动影响全局行为的能力:
| 能力 | `OPINIONATED` 默认 | `CONSERVATIVE` 默认 | 说明 |
| --- | --- | --- | --- |
| traceId / MDC / 日志 pattern / 响应头 | 开启 | 关闭 | 影响用户自己的日志输出 |
| Controller 调用日志 | 开启 | 关闭 | Web 环境下自动记录请求调用 |
| Feign 调用日志 | 开启 | 关闭 | 存在 Feign 时自动记录远程调用 |
| Jackson 增强 | 开启 | 关闭 | 影响 JSON 序列化、反序列化扩展 |
| Spring Converter / Web MVC 日期绑定 | 开启 | 关闭 | 影响字符串到日期时间的全局转换 |
| MyBatis-Plus 拦截器 | 开启 | 关闭 | 自动补充分页、乐观锁、防全表更新 |
| RedisTemplate 自动补齐 | 开启 | 关闭 | 依赖 Redis classpath 与连接工厂 |
| Redis Cache 自动补齐 | 开启 | 关闭 | 依赖 Spring Cache / Redis 条件 |
| Excel converter 自动注册 | 开启 | 关闭 | helper 工具类不受影响 |
## Maven 依赖
最新版本
[](https://central.sonatype.com/artifact/io.github.luminion/velo-spring-boot3-starter)
### Spring Boot 2
```xml
io.github.luminion
velo-spring-boot2-starter
${velo.version}
```
### Spring Boot 3
```xml
io.github.luminion
velo-spring-boot3-starter
${velo.version}
```
### Spring Boot 4
```xml
io.github.luminion
velo-spring-boot4-starter
${velo.version}
```
### 编译参数建议
建议业务项目开启 Java 编译参数 `-parameters`,以支持 SpEL key 引用方法参数名,例如 `#userId`,未开启时只能为 `#p0`、`#p1`等:
```xml
org.apache.maven.plugins
maven-compiler-plugin
true
```
---
## 各功能细览
### 1. 缓存自动配置
Velo 会在满足 Redis Cache 条件时补齐 `CacheManager`、`RedisCacheConfiguration` 和分 cache TTL 配置。
额外依赖:
```xml
org.springframework.boot
spring-boot-starter-cache
org.springframework.boot
spring-boot-starter-data-redis
```
关键配置:
```yaml
velo:
cache:
enabled: true
prefix: app
separator: ":"
default-ttl: 5m
ttl-jitter-percentage: 0
ttl:
user: 10m
order: 30m
```
使用示例:
```java
@EnableCaching
@SpringBootApplication
public class DemoApplication {
}
```
```java
@Cacheable(cacheNames = "user", key = "#id")
public UserDTO getById(Long id) {
return null;
}
```
说明:
- `velo.cache.enabled` 默认开启
- 默认只在 `spring.cache.type=redis` 或未显式指定时接管 Redis Cache
- `default-ttl` 默认 `5m`
- `ttl.` 可按缓存名单独覆盖 TTL
- key 前缀格式为 `prefix + separator + cacheName + separator`
- 业务侧仍然需要自己开启 `@EnableCaching`
缓存雪崩防护(TTL 抖动):
- `ttl-jitter-percentage` 默认 `0`(关闭),有效范围为 `0..100`。设为 `10` 表示每条缓存写入时 TTL 在原值 ±10% 内随机偏移;超出范围会导致应用启动失败
- 抖动在**每次写入时按 key 独立计算**,因此同一缓存名称下不同 key 也会获得不同过期时间,可同时缓解「不同缓存类型同时过期」和「同一类型大量 key 同时过期」两类雪崩
- 抖动只影响实际写入 Redis 的过期时间,不改变 `default-ttl` / `ttl.` 的配置语义
### 2. Excel 自动配置
Velo 提供两层能力:
- Excel helper 工具类,随依赖引入即可直接使用
- 扩展 converter 自动注册,需显式开启 `velo.excel.converters.enabled`
可选额外依赖,按实际使用的库引入:
```xml
com.alibaba
easyexcel
```
```xml
cn.idev.excel
fastexcel
```
```xml
org.apache.fesod
fesod-sheet
```
关键配置:
```yaml
velo:
excel:
enabled: true
converters:
enabled: true
boolean-enabled: true
long-enabled: true
float-enabled: true
double-enabled: true
big-integer-enabled: true
big-decimal-enabled: true
date-enabled: true
local-date-time-enabled: true
local-date-enabled: true
local-time-enabled: true
```
使用示例:
```java
List> converters = EasyExcelHelper.createExtraConverters(
"yyyy-MM-dd",
"HH:mm:ss",
"yyyy-MM-dd HH:mm:ss",
"GMT+8"
);
EasyExcelHelper.registerConverters(converters);
```
说明:
- `velo.excel.enabled` 默认开启
- `velo.excel.converters.enabled` 默认开启
- 一旦开启,starter 会根据 classpath 自动尝试向 EasyExcel、FastExcel、Fesod 注册扩展 converters
- 时间、日期、时区格式统一复用 `velo.date-time-format.*`
- 如果你只想手工控制注册时机,也可以直接使用 `EasyExcelHelper`、`FastExcelHelper`、`FesodExcelHelper`
### 3. 幂等
`@Idempotent` 用于防重复提交,默认即可使用。
可选额外依赖:
- 需要 Redisson 后端时引入 `org.redisson:redisson-spring-boot-starter`
- 需要 Redis 后端时引入 `spring-boot-starter-data-redis`
- 需要 Caffeine 后端时引入 `com.github.ben-manes.caffeine:caffeine`
关键配置:
```yaml
velo:
idempotent:
enabled: true
backend: AUTO
prefix: "idempotent:"
```
使用示例:
```java
import io.github.luminion.velo.idempotent.annotation.Idempotent;
@Idempotent(key = "#userId", ttl = 3000)
public void submitOrder(Long userId) {
// ...
}
```
说明:
- `backend` 可选 `AUTO`、`REDISSON`、`REDIS`、`CAFFEINE`、`JDK`
- `AUTO` 模式下按自动配置顺序选择后端:`REDISSON -> REDIS -> CAFFEINE -> JDK`
- `prefix` 默认 `idempotent:`
- `ttl` 单位固定为毫秒,默认 `3000`(3 秒)
- 业务失败(抛异常)时会清除本次幂等记录以允许重试;清除采用 token 比对,只删除本次请求写入的记录,不会误删并发请求在窗口内刚写入的新记录
- 幂等 key 始终以方法(`全限定类名#方法名(参数类型...)`)为前缀,再拼接 SpEL 结果,与限流分桶语义一致:**不同方法或同名重载方法即使用相同的 SpEL key(如都用 `#orderId`)也不会互相碰撞、共享同一幂等窗口**
> ⚠️ `key` 必须显式指定。`key` 为空时会退化成 `全限定类名#方法名(参数类型...)`,意味着**该方法的所有调用(不分参数、不分调用者)共享同一个幂等窗口**,这通常不是期望行为。此时 starter 会打印一条 WARN 提醒。
>
> ```java
> // ❌ 危险:userId=1 提交后,3 秒内 userId=2 也会被拦截
> @Idempotent(ttl = 3000)
> public void submitOrder(Long userId) { }
>
> // ✅ 正确:每个用户独立幂等
> @Idempotent(key = "#userId", ttl = 3000)
> public void submitOrder(Long userId) { }
> ```
>
> 若确实需要「全局同一时刻只能执行一次」的语义(如系统级初始化),更推荐用 `@Lock`。
### 4. 限流
`@RateLimit` 用于方法级限流,适合接口限流、用户维度限流和资源维度限流。
可选额外依赖:
- 需要 Redisson 后端时引入 `org.redisson:redisson-spring-boot-starter`
- 需要 Redis 后端时引入 `spring-boot-starter-data-redis`
- 需要 Caffeine 后端时引入 `com.github.ben-manes.caffeine:caffeine`
关键配置:
```yaml
velo:
rate-limit:
enabled: true
backend: AUTO
prefix: "rateLimit:"
```
使用示例:
```java
import io.github.luminion.velo.ratelimit.annotation.RateLimit;
@RateLimit(key = "#userId", permits = 10, window = 1000)
public Object query(Long userId) {
return null;
}
```
说明:
- `permits` 表示一个时间窗口内允许通过的最大请求数
- `window` 定义窗口大小,单位固定为毫秒,默认 `1000`(1 秒)
- `backend` 与幂等一致,也支持 `AUTO/REDISSON/REDIS/CAFFEINE/JDK`
- `AUTO` 模式下默认选择顺序同幂等:`REDISSON -> REDIS -> CAFFEINE -> JDK`
- `REDIS` 后端使用 Boot 默认的 `stringRedisTemplate` 执行 Lua,脚本通过 Redis `TIME` 获取统一时钟,不受应用节点时间偏差影响
关于 `key` 的分桶语义(重要):
- `key` 为空:方法级全局限流,该方法的**所有调用者共享同一个配额**
- `key` 非空:按 SpEL 表达式结果分桶,**每个桶独立计算配额**
| 写法 | 实际行为 |
| --- | --- |
| `@RateLimit(permits=10)` | 所有调用共享 10 次/窗口 |
| `@RateLimit(key="#userId", permits=10)` | 每个 userId 独立 10 次/窗口 |
> ⚠️ 如果你期望「每个用户 / 每个资源独立限流」,必须显式指定 `key`,否则会退化为全局共享配额。
关于小数 `permits`:
`permits` 支持小数,用于表达「低于 1 次 / 窗口」的限流需求。换算规则:
- 实际容量 `capacity = ceil(permits)`(向上取整)
- 实际窗口 `interval = window × (capacity / permits)`(拉长窗口以保持平均速率)
| 配置 | 含义 | 实际实现 |
| --- | --- | --- |
| `permits=10, window=1000` | 10 次/秒 | 容量=10,窗口=1000ms |
| `permits=0.5, window=1000` | 0.5 次/秒(即 2 秒 1 次) | 容量=1,窗口=2000ms |
| `permits=0.2, window=1000` | 0.2 次/秒(即 5 秒 1 次) | 容量=1,窗口=5000ms |
多数场景用整数更直观,例如「每 5 秒 1 次」可直接写 `@RateLimit(permits=1, window=5000)`,等价于 `permits=0.2, window=1000`。
### 5. 锁
`@Lock` 提供方法级互斥能力,适合支付、状态流转、扣减等需要串行化的业务场景。
可选额外依赖:
- 需要 Redisson 后端时引入 `org.redisson:redisson-spring-boot-starter`
- 需要 Redis 后端时引入 `spring-boot-starter-data-redis`
- 需要 Caffeine 后端时引入 `com.github.ben-manes.caffeine:caffeine`
关键配置:
```yaml
velo:
lock:
enabled: true
backend: AUTO
prefix: "lock:"
retry-interval: 10ms
```
使用示例:
```java
import io.github.luminion.velo.lock.annotation.Lock;
@Lock(key = "#orderId", waitTimeout = 1000, lease = 30000)
public void pay(Long orderId) {
// ...
}
```
说明:
- `backend` 也支持 `AUTO`、`REDISSON`、`REDIS`、`CAFFEINE`、`JDK`
- `AUTO` 默认顺序为 `REDISSON -> REDIS -> CAFFEINE -> JDK`
- `waitTimeout` 单位固定为毫秒,默认 `0`,表示拿不到锁立即失败
- `retry-interval` 默认 `10ms`,仅用于简单 Redis 后端等待锁时的轮询;值越小获取越及时,但 Redis 请求频率越高
- `lease` 单位固定为毫秒,默认 `30000`(30 秒)
- `REDIS` / `REDISSON` 更适合分布式场景,`CAFFEINE` / `JDK` 只保证单 JVM 内互斥
- 本地锁只有一份实现:Caffeine 是纯缓存库、不提供互斥锁 API,因此 `CAFFEINE` 档位与 `JDK` 完全一致(复用同一实现),`backend=CAFFEINE` 仍可用,只是不再单独维护
- `REDIS` 后端支持同线程可重入(同一线程重复加同一把锁不会自锁死),最外层释放时才真正删除 Redis 锁
- `key` 为空时降级为方法级锁(基于 `全限定类名#方法名(参数类型...)`),表示「该方法全局串行执行」,是一个有意义的语义,因此安静降级、不打告警;需要按业务维度加锁时请显式指定,例如 `@Lock(key = "#orderId")`
### 6. 并发控制组合顺序
当 `@Idempotent`、`@RateLimit`、`@Lock` 同时作用于同一个方法时,starter 内置顺序为:
```text
@Idempotent -> @RateLimit -> @Lock -> 业务方法
```
这意味着重复提交会最先被拒绝,不消耗限流令牌,也不会尝试加锁;限流失败时不会进入锁等待;只有真正允许执行业务的方法调用才会获取锁。
这些切面使用接近 `Ordered.LOWEST_PRECEDENCE` 的低优先级顺序值,并在三者之间保留较大间隔,便于业务自定义切面通过 `@Order` 插入到合适位置。
### 7. 日志
Velo 提供一套统一调用日志能力。Controller、Feign 与 `@InvokeLog` 每次调用分别输出进入和退出两条记录:进入记录包含入参,退出记录包含耗时以及返回值或异常。
日志序列化器或 `InvocationLogWriter` 发生运行时异常时会记录内部 WARN 并丢弃本次日志,不会阻止业务执行或覆盖原始业务异常。
基础 starter 默认可用,无需额外依赖。
关键配置:
```yaml
velo:
log:
enabled: true
level: INFO
slow:
level: WARN
trace:
enabled: true
header-name: X-Trace-Id
mdc-key: traceId
response-header-enabled: true
feign-propagation-enabled: true
logging-pattern-enabled: true
invocation:
enabled: true
max-payload-length: -1
include-args: true
include-result: true
include-error-stack-trace: false
controller:
enabled: true
feign:
enabled: true
method:
enabled: true
```
使用示例:
```java
import io.github.luminion.velo.log.annotation.InvokeLog;
import io.github.luminion.velo.log.annotation.SlowLog;
@InvokeLog
@SlowLog(300)
public Object createOrder(CreateOrderCmd cmd) {
return null;
}
```
说明:
- `traceId` 默认开启,会写入 MDC、响应头,并在 Feign 调用中透传
- 如果没有自定义 `logging.pattern.level`,会自动把 `%X{traceId}` 加到用户自己的日志中
- Controller、Feign 与 `@InvokeLog` 的进入日志格式为 `[target] ==> args=...`
- Controller、Feign 与 `@InvokeLog` 的退出日志格式为 `[target] <== cost=Xms result=...`;调用失败时输出异常摘要并使用 ERROR 级别
- `@SlowLog` 的阈值单位固定为毫秒,只在调用耗时超过阈值后输出一条独立慢日志,格式包含 `cost=Xms threshold=Yms`
- 慢日志级别由 `velo.log.slow.level` 控制,默认 WARN;调用异常且超过阈值时提升为 ERROR,设置为 `OFF` 时完全关闭独立慢日志
- 同时命中其他调用日志切面时,慢日志默认在 ENTRY、EXIT 日志之后最后输出
- 如果需要写入 MQ、数据库或审计系统,提供自定义 `InvocationLogWriter` Bean 即可
- `velo.log.level=OFF` 会关闭 Controller、Feign、`@InvokeLog` 的成功和异常输出;`velo.log.slow.level=OFF` 会关闭 `@SlowLog` 的独立慢日志;自定义 `InvocationLogWriter` 不受这些日志级别约束
敏感参数不打印(`@LogPayloadIgnore`):
如果某些方法的入参或返回值包含密码、token 等敏感信息,可用 `@LogPayloadIgnore` 抑制其打印。被忽略的内容在日志中显示为 `-`,但调用本身(方法名、耗时、成功/异常状态)仍会记录。该注解对 Controller、Feign、`@InvokeLog`、`@SlowLog` 所有调用日志切面均生效,可标注在方法或类上。
```java
import io.github.luminion.velo.log.annotation.LogPayloadIgnore;
// 同时忽略入参与返回值
@LogPayloadIgnore
public void deleteUser(Long userId) { }
// 只忽略返回值,仍打印入参
@LogPayloadIgnore(args = false)
public UserDTO login(LoginRequest req) { }
// 只忽略入参,仍打印返回值
@LogPayloadIgnore(result = false)
public Token issueToken(Credential credential) { }
```
> 说明:starter 不内置基于字段名正则的自动脱敏,敏感信息控制统一通过 `@LogPayloadIgnore` 按方法显式声明,语义更明确、无误伤风险。
### 7. XSS
XSS 清洗能力挂在 `velo.web.xss.*` 下,默认关闭。
额外依赖:
```xml
org.springframework.boot
spring-boot-starter-web
org.jsoup
jsoup
```
关键配置:
```yaml
velo:
web:
xss:
enabled: true
strategy: RELAXED
```
使用示例:
```java
public class UserQuery {
private String keyword;
@XssIgnore
private String rawHtml;
}
```
说明:
- `velo.web.xss.enabled` 默认 `false`
- `strategy` 可选 `NONE`、`ESCAPE`、`SIMPLE_TEXT`、`BASIC`、`BASIC_WITH_IMAGES`、`RELAXED`
- `ESCAPE` 不依赖 `jsoup`;其他 HTML 清洗策略必须引入 `jsoup`
- `ESCAPE` 且无 `jsoup` 时会走 Spring 转义;其他策略缺少 `jsoup` 时只打印 WARN,不注册 `XssCleaner`,也不会自动降级
- 清洗发生在 Web MVC 的字符串参数绑定阶段,包括 query/form/path 和普通对象参数中通过 MVC binder 绑定的 `String` 字段;不会接管 Jackson JSON 请求体反序列化,也不会全局处理所有字符串字段
### 8. Jackson
Jackson 增强是基础 starter 的核心能力之一,会统一处理日期时间、超大整数、枚举派生字段和字符串转换。
基础 starter 默认可用,无需额外依赖。
关键配置:
```yaml
velo:
jackson:
enabled: true
date-time-enabled: true
serialize-long-as-string: true
serialize-big-decimal-as-string: true
serialize-floating-as-string: false
enum-desc-enabled: true
enum-name-suffix: name
string-converter-enabled: true
enum-mappings:
code: name
key: value
```
使用示例:
```java
public class OrderVO {
@JsonEnum(OrderStatusEnum.class)
private Integer status;
@JsonEncode(PhoneMasker.class)
private String mobile;
@JsonDecode(EmailMasker.class)
private String email;
}
```
说明:
- Boot 2 / 3 使用 Jackson 2 自动配置,Boot 4 使用 Jackson 3 自动配置
- `serialize-long-as-string=true` 时,`Long` / `BigInteger` 在**序列化(写出给前端)**时统一转为字符串,避免 JS Number 超过 2^53 精度丢失
- 这些 `serialize-*` 开关**只影响序列化方向**;反序列化(前端传入)时数字和字符串都能正常绑定,无需前端特殊处理
- `serialize-big-decimal-as-string=true` 默认开启
- `enum-desc-enabled=true` 时,`@JsonEnum` 可为数值字段派生出描述字段,例如 `statusName`
- `string-converter-enabled=true` 时,`@JsonEncode` / `@JsonDecode` 会按函数类做字符串转换
- 日期时间格式依然复用 `velo.date-time-format.*`
### 9. MyBatis-Plus 自动配置
Velo 会在满足条件时自动创建 `MybatisPlusInterceptor`,并按开关补充分页、乐观锁、防全表更新拦截器。
额外依赖:
Spring Boot 2:
```xml
com.baomidou
mybatis-plus-boot-starter
```
Spring Boot 3:
```xml
com.baomidou
mybatis-plus-spring-boot3-starter
```
Spring Boot 4:
```xml
com.baomidou
mybatis-plus-spring-boot4-starter
```
关键配置:
```yaml
velo:
mybatis-plus:
enabled: true
pagination-enabled: true
optimistic-locker-enabled: true
block-attack-enabled: true
```
说明:
- `velo.mybatis-plus.enabled` 默认开启
- 若容器里已经存在同类 `InnerInterceptor` Bean,starter 不会覆盖
- 默认会把当前容器中的 `InnerInterceptor` 汇总进 `MybatisPlusInterceptor`
### 10. Redis 自动配置
Velo 会基于已有 `RedisConnectionFactory` 和 `RedisSerializer