Under-Utils
Under-Utils 是一组面向 Java 21 / Spring Boot 项目的工程模式工具包,用来沉淀业务系统里反复出现、实现细节多、容易写散的基础设施代码。
中文 | English
Under-Utils 是一组面向 Java 21 / Spring Boot 项目的工程模式工具包,用来沉淀业务系统里反复出现、实现细节多、容易写散的基础设施代码。
这个项目不定位为 Hutool、Apache Commons 或 Guava 的替代品。新增能力应解决可复用的工程问题,并且有明确行为可以测试,例如请求上下文传播、限流、防重复提交、Redis 分布式锁、缓存重建、OpenAPI 客户端治理、AI 模型基础调用、安全分页、审计填充和导入任务流程。
当前稳定版本:1.0.2。main 分支当前为 1.0.3-SNAPSHOT 开发周期。
Maven 坐标使用 GitHub namespace io.github.yexianglun-d。Java 包名在 1.x 内继续保持
com.undernine.utils,这是为了避免已发布 public API 发生包名级破坏性迁移。
项目边界
适合进入本项目的能力,应有清晰复用边界,并能封装足够多的重复复杂度。
适合的方向:
- 跨服务复用的基础设施模式,而不是单个应用的业务规则。
- 具备明确失败语义、资源边界和测试覆盖的能力。
- 发布后 API 可以保持稳定。
- 外部系统依赖被收口在小而清晰的接口后面。
不适合的方向:
- JDK、Spring、Hutool、Apache Commons、Guava 已成熟覆盖的小工具方法。
- 只服务单个业务线的一次性流程。
- 没有错误处理、并发边界或测试覆盖的快捷封装。
under-utils-core 中保留了一些历史静态工具类,用于兼容已有调用;它们不是后续新增能力的主线。
模块依赖重量和拆分判断见 docs/DEPENDENCY_REVIEW.md。 工程成熟度推进见 docs/ENGINEERING_MATURITY.md,后续功能孵化见 docs/FUTURE_FEATURES.md。 Crypto 重新建模和 core JSON 迁移分别见 docs/CRYPTO_REDESIGN.md 与 docs/JSON_MODULE_MIGRATION.md。
模块
| 模块 | 说明 |
|---|---|
under-utils-bom |
统一管理 Under-Utils 模块和相关依赖版本。 |
under-utils-core |
低耦合基础能力,例如雪花 ID、金额工具;历史静态工具仅做兼容维护。 |
under-utils-spring |
Spring Web 上下文传播、限流/防重抽象、返回结果、异常处理和 JSON 脱敏。 |
under-utils-redis |
基于 Redisson 的分布式锁、限流/防重存储、cache-aside、逻辑过期缓存模板、内置指标和可选 Micrometer 观测适配。 |
under-utils-http |
HTTP 便捷调用与 OpenAPI 客户端治理,包括 token 刷新、签名、trace/idempotency header、错误解码和重试。 |
under-utils-ai |
OpenAI-compatible AI 大模型基础调用封装,覆盖同步/流式文本对话、命名客户端注册表、provider 扩展、响应元数据、基础错误分类和敏感信息脱敏。 |
under-utils-mybatis |
MyBatis-Plus 安全分页、排序白名单、审计填充和分页结果封装。 |
under-utils-biz |
可复用业务流程模板,目前主要是 CSV 导入、异步导入进度查询和错误导出。 |
under-utils-ai-starter |
Spring Boot AI 自动装配入口,按配置创建默认或多个命名 AiClient。 |
under-utils-spring-starter |
Spring Boot 自动装配入口,只包含 Spring 本地横切能力。 |
under-utils-redis-starter |
Spring Boot Redis 自动装配入口,包含 Spring starter 并接入 Redis 分布式能力。 |
under-utils-starter |
兼容聚合 starter,继续覆盖 Spring 与 Redis 自动装配。 |
under-utils-samples |
可运行示例工程,不作为正式 Maven 库构件发布。 |
under-utils-test |
Testcontainers 集成测试模块,仅通过 integration-tests profile 启用。 |
环境要求
- Java 21
- Maven 3.9+
- Spring Boot 3.1.x
- Docker,仅在运行 Testcontainers 集成测试或 Redis 示例环境时需要
安装
建议先引入 BOM,再按需引入 starter 或单模块。1.0.2 起普通 Spring Boot 服务优先按需选择轻量 starter:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-bom</artifactId>
<version>1.0.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-spring-starter</artifactId>
</dependency>
</dependencies>
只需要 Spring 本地横切能力时使用:
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-spring-starter</artifactId>
</dependency>
如果需要 Redis 分布式锁、Redis 限流/防重或缓存模板,使用 Redis starter:
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-redis-starter</artifactId>
</dependency>
旧入口 under-utils-starter 会保留为聚合 starter,适合暂时不调整依赖坐标的项目。
如果只需要 AI 大模型基础调用封装,单独引入:
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-ai</artifactId>
</dependency>
Spring Boot 项目需要按配置创建默认 AiClient 时,引入独立 AI starter:
<dependency>
<groupId>io.github.yexianglun-d</groupId>
<artifactId>under-utils-ai-starter</artifactId>
</dependency>
本地开发:
git clone https://github.com/yexianglun-d/java-tool-box.git
cd java-tool-box
mvn test
Starter 示例
starter 默认使用本地内存状态存储。切换到 Redis 前,业务项目需要先提供 RedissonClient。
under:
utils:
web:
operation-context:
enabled: true
task-decorator-enabled: true
rate-limit:
enabled: true
store: redis
repeat-submit:
enabled: true
store: redis
redis:
lock-enabled: true
cache:
enabled: true
ttl: 5m
null-ttl: 30s
jitter: 10s
cache-null: true
key-prefix: "app:cache:"
rebuild-lock-enabled: true
logical-cache:
enabled: true
logical-ttl: 5m
physical-ttl: 30m
cache-null: true
key-prefix: "app:logical-cache:"
observation:
enabled: true
限流和防重复提交默认失败语义是拒绝请求并抛出 BizException,异常消息来自注解配置。本地 store 只在当前 JVM 内生效,多实例部署应使用 Redis 或自定义 RateLimitStore / RepeatSubmitStore。
存在 MeterRegistry 且没有自定义 CacheOperationObserver 时,Redis starter 会自动接入 Micrometer 缓存观测;需要关闭时设置 under.utils.redis.observation.enabled=false。
使用示例
请求上下文传播:
OperationContext context = OperationContextHolder.getContext();
String traceId = context == null ? null : context.getTraceId();
Runnable task = OperationContextSnapshot.capture().wrap(() -> {
OperationContext asyncContext = OperationContextHolder.getContext();
});
限流和防重复提交:
@RateLimit(limit = 10, period = 60, message = "请求过于频繁")
@PostMapping("/sms/send")
public void sendSms(@RequestBody SendSmsCommand command) {
smsService.send(command);
}
@PreventRepeat(timeout = 5, message = "请勿重复提交")
@PostMapping("/orders")
public Long createOrder(@RequestBody CreateOrderCommand command) {
return orderService.create(command);
}
Redis cache-aside:
UserProfile profile = cacheAsideTemplate.get(
"user:profile:" + userId,
UserProfile.class,
() -> userRepository.findProfile(userId)
);
异步导入任务:
AsyncImportTaskTemplate importTasks = new AsyncImportTaskTemplate(executor);
String taskId = importTasks.submit(rows, handler);
ImportProgress progress = importTasks.findProgress(taskId).orElseThrow();
安全分页:
SortFieldMapping mapping = SortFieldMapping.builder()
.add("createdAt", "create_time")
.add("status", "status")
.build();
SafePageQuery query = SafePageQuery.of(page, size)
.orderByDesc("createdAt");
示例工程
mvn -pl under-utils-samples -am spring-boot:run
示例工程默认端口为 18080,默认不依赖 Redis 或 MySQL。Redis 示例和请求样例见 under-utils-samples/README.md。
验证
默认检查:
mvn -DskipTests compile
mvn test
发布构件检查:
mvn -Prelease -DskipTests package
Testcontainers 集成测试:
mvn -Pintegration-tests -pl under-utils-test -am test
public API 兼容性检查:
mvn -Papi-compat \
-pl under-utils-core,under-utils-http,under-utils-spring,under-utils-redis,under-utils-mybatis,under-utils-biz \
-am \
-DskipTests \
verify
api-compat profile 会把当前构件和 1.0.1 已发布构件做 public API 对比。默认覆盖稳定运行时模块;starter 拆分属于模块边界迁移,当前通过自动装配测试和文档记录维护兼容性。
发布流程见 docs/RELEASE.md。
贡献
提交新能力前请先阅读 CONTRIBUTING.md。核心判断是:这个能力是否属于可复用工程模式,而不是应用代码、框架已有能力或成熟工具库已有能力。
public API 变更遵循 docs/COMPATIBILITY.md。除非有明确的安全或正确性例外,patch 和 minor 版本应保持源码兼容。
许可证
Under-Utils 使用 MIT License。