别再写 CommonUtil 了:Spring Boot 项目工具类设计指南
欢迎阅读我的文章!更多精彩内容,欢迎关注:
• B站主页:小枫Geek
• 微信公众号:Procode
在很多 Spring Boot 项目中,经常会出现一种很典型的现象:util 包越来越大,StringUtils、DateUtils、UserUtils、OrderUtils、CommonUtils……工具类越写越多,最终项目里充斥着大量 static 方法。
一开始大家写工具类是为了“方便复用”,但时间一长就会发现—— 代码虽然能跑,但项目结构却越来越混乱,逻辑难以维护。
工具类本来是为了提升效率,但如果不 加控制,就会变成一种 架构层面的技术债务。今天我们就系统聊一聊:Spring Boot 项目为什么容易工具类泛滥?又该如何优雅避免?
1、为什么容易出现工具类泛滥
工具类泛滥并不是 Spring Boot 的问题,而是 开发习惯 + 架构设计问题。
常见原因主要有四个。
1. 开发者习惯把“通用逻辑”丢进 Util
很多人遇到可复用代码时,第一反应是:
新建一个 Util
比如:
DateUtil.format()UserUtil.getCurrentUser()OrderUtil.calculatePrice()
这样写短期看起来很方便,但实际上隐藏了问题:
-
业务逻辑被“工具化”
-
代码语义变得模糊
-
类的职责不清晰
例如:
OrderUtil.calculateDiscount()
这个逻辑其实属于 订单领域逻辑,而不是工具类。
2. 静态方法导致无法管理依赖
工具类一般都是:
public class XxxUtil { public static void doSomething(){ }}
问题在于:static 方法无法被 Spring 管理。
这就带来几个问题:
-
1.无法注入 Bean
-
2.不方便做 AOP
-
3.不方便测试 Mock
例如:
UserUtil.getCurrentUser()
如果后续用户来源变成 网关解析 / Token 解析 / Redis 缓存, 工具类就很难扩展。
3. 逻辑聚合越来越混乱
随着项目发展,工具类往往变成这样:
StringUtilDateUtilCollectionUtilCommonUtilBusinessUtil
其中最危险的是:
CommonUtil
这是一个“万物归一类”。
项目后期你会发现:这个类已经有 2000 行代码。
4. 工具类破坏面向对象设计
工具类的本质是:面向过程编程。
而 Java 和 Spring Boot 的设计哲学是:面向对象 + 依赖注入。
当项目大量使用工具类时,会出现:
-
业务逻辑散落
-
类之间关系断裂
-
难以扩展
从架构角度来看,这是 代码结构退化。
2、哪些代码才适合放工具类
并不是说 工具类完全不能用。
关键是:工具类只应该放“无状态通用逻辑”。
典型例子包括:
1. 字符串处理
例如:
StringUtils.isBlank()StringUtils.camelToUnderline()
这种逻辑:
-
无状态
-
无业务含义
-
高度复用
适合工具类。
2.日期时间处理
例如:
DateUtils.format()DateUtils.parse()
因为 Java 原生日期 API 比较复杂, 封装工具类可以简化使用。
3.加密与编码
例如:
MD5Util.encrypt()Base64Util.encode()
这些属于 纯算法逻辑。
4.文件操作
例如:
FileUtil.readFile()FileUtil.writeFile()
也属于底层能力。
总结一句话:工具类只负责“技术能力”,不负责“业务逻辑”。
3、业务逻辑不要放工具类
一个非常重要的原则:业务逻辑必须属于业务对象。
例如:
错误写法:
OrderUtil.calculatePrice(order)
正确写法:
orderService.calculatePrice(order)
或者:
order.calculatePrice()
业务逻辑应该放在:
-
Service
-
Domain
-
Strategy
而不是 Util。
4、Spring Bean 替代工具类
如果某段逻辑:
-
需要依赖其他组件
-
需要扩展
-
可能会改变
那就不要写工具类。直接写 Spring Bean。
例如:
错误写法:
UserUtil.getCurrentUser()
推荐写法:
@Componentpublic class UserContext { public User getCurrentUser(){ ... }}
使用时:
@AutowiredUserContext userContext;userContext.getCurrentUser();
这样做的好处:
1 可以依赖注入
2 可以做 AOP
3 可以做单元测试
4 可以替换实现
这就是 Spring 的优势。
5、使用领域服务代替 BusinessUtil
很多项目会有这种类:
BusinessUtil
里面有:
calculateDiscount()checkOrderStatus()verifyUserPermission()
这是典型的 领域逻辑混乱。
正确方式是:把逻辑放回领域。
例如:
DiscountServicePermissionServiceOrderDomainService
这样:
-
职责清晰
-
模块清晰
-
可扩展
6、利用设计模式减少工具类
工具类泛滥,本质上是因为:缺少设计抽象。
几个常见替代模式:
1. 策略模式
例如不同折扣计算:
错误:
DiscountUtil.calculate(type)
正确:
DiscountStrategyVipDiscountStrategyNormalDiscountStrategy
2.工厂模式
例如对象创建:
错误:
ObjectUtil.createUser()
正确:
UserFactory.create()
3. 领域模型
例如订单逻辑:
错误:
OrderUtil.pay()
正确:
order.pay()
这是 领域驱动设计(DDD)思想。
7、合理规划工具类包结构
如果项目确实需要工具类,建议进行分类管理。
例如:
util
├──date
│
└──DateUtils
├──string
│ └──StringUtils
├──file
│ └──FileUtils
└──crypto
└──EncryptUtils
不要出现:
CommonUtilSystemUtilBusinessUtil
这些都是 设计失控的信号。
8、判断标准
如果你写代码时准备新建工具类,可以问自己三个问题:
1.这个逻辑是不是业务逻辑?
如果是 → 放 Service。
2.这个逻辑是否需要依赖 Bean?
如果是 → 写 Spring Component。
3.这个逻辑是否纯粹通用?
如果是 → 才写 Util。
小结
工具类本身没有问题,但滥用工具类会破坏项目结构。
在 Spring Boot 项目中,一个健康的结构应该是:
Controller
↓Service
↓Domain /Repository
而工具类应该只扮演:底层能力库 的角色。
记住一句经验之谈:能写 Bean 就不要写 Util,能写领域对象就不要写静态方法。
当代码真正按照职责划分时,项目会变得非常清晰—— 每个类都在做自己该做的事情。那时候再回头看那些 3000 行的 CommonUtil,会感觉像是程序员成长路上的“化石”。
-END-
更多推荐

所有评论(0)