对比这两种 JWT 工具类的设计风格,是一个非常棒的技术分享主题,它能清晰地展示出“配置与代码分离”以及“依赖注入”在现代软件开发中的重要性。
JWT 工具类设计的“两种境界”:静态工具 vs. Spring Bean ⚔️
嘿,各位后端开发者!👋 在构建需要身份认证的系统时,JWT (JSON Web Token) 无疑是我们的首选方案。而在 Java 项目中,我们通常会创建一个 JwtUtil 或 JwtUtils 的工具类来封装 Token 的生成和验证逻辑。
但是,这个小小的工具类,却有两种截然不同的设计“境界”:
- 传统静态工具类 (
static方法):简单直接,随处可用。 - 现代 Spring Bean (
@Component注入):拥抱框架,灵活可配。
这两种方式都能完成任务,但它们在可维护性、可测试性和安全性上却有着天壤之别。今天,我们就结合具体的代码,深入剖析这两种设计方式的优劣,看看你的项目正处于哪个“境界”,以及如何向更现代、更健壮的设计演进。
🎯 核心差异速览
| 特征 | 传统静态工具类 (JwtUtils) | 现代 Spring Bean (JwtUtil) |
|---|---|---|
| 设计思想 | 面向过程,功能集合 | 面向对象,依赖注入 (DI) ✅ |
| 配置管理 | 硬编码在代码中 ❌ | 通过 application.yml 集中管理 ✅ |
| 灵活性 | 低,修改配置需改代码并重新部署 | 高,修改配置只需重启或动态刷新 |
| 可测试性 | 困难,静态方法难以模拟 (Mock) | 简单,可轻松模拟 Bean 的行为 ✅ |
| 与框架关系 | 游离于 Spring 体系之外 | 与 Spring 生态无缝集成 ✅ |
📜 境界一:简单直接的静态工具类 (JwtUtils)
这是很多开发者入门时最自然的选择。我们把所有功能方法都声明为 static,方便在任何地方直接通过类名调用。
代码实现 (JwtUtils.java)
package com.productQualification.common.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
// ... 其他 imports ...
import java.util.Calendar;
import java.util.Date;
public class JwtUtils {
public static String createToken(String userId, String type, String userName) {
// 1. 有效期被硬编码为 1 天
Calendar nowTime = Calendar.getInstance();
nowTime.add(Calendar.DAY_OF_YEAR, 1);
Date expiresDate = nowTime.getTime();
return JWT.create().withAudience(userId)
.withIssuedAt(new Date())
.withExpiresAt(expiresDate)
.withClaim("userName", userName)
.withClaim("type", type)
// 2. 密钥是根据 userId 和一个硬编码的盐值 "clear" 动态生成的
.sign(Algorithm.HMAC256(userId + "clear"));
}
public static void verifyToken(String token, String secret) throws TokenException {
// 验证时,也需要用 userId + "clear" 来构造密钥
JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret + "clear")).build();
verifier.verify(token);
// ... 异常处理 ...
}
// ... 其他静态方法 ...
}
调用方式
// 在 Service 中直接调用
String token = JwtUtils.createToken("123", "user", "Alice");
优点与“陷阱”
这种方式的优点是简单。但它的“陷阱”也正源于此:它将易变的信息(配置)和不变的逻辑(代码)耦合在了一起。
- 想改有效期? -> 修改代码,重新编译,重新部署。
- 想换加密盐值? -> 修改代码,重新编译,重新部署。
- 想写单元测试? -> 无法模拟
JwtUtils.createToken的行为,测试变得困难。
✨ 境界二:拥抱框架的 Spring Bean (JwtUtil)
在 Spring Boot 的世界里,我们有更好的选择。通过将工具类声明为一个 @Component,我们可以利用 Spring 强大的依赖注入和配置管理能力。
配置文件 (application.yml)
首先,我们将所有易变的信息抽离到配置文件中。
# application.yml
jwt:
secret: "your-super-secret-key-for-jwt-that-is-long-and-random"
expiration: 604800000 # 7天的毫秒数
代码实现 (JwtUtil.java)
package com.productQualification.suitselection.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
// ... 其他 imports ...
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component // 1. 声明为 Spring 组件 (Bean)
public class JwtUtil {
// 2. 从 application.yml 注入密钥
@Value("${jwt.secret}")
private String secret;
// 3. 从 application.yml 注入过期时间
@Value("${jwt.expiration}")
private long expiration;
// 注意:方法不再是 static 的
public String createToken(Integer userId, String openId, String userType) {
Date now = new Date();
// 4. 使用注入的配置值
Date expiryDate = new Date(now.getTime() + expiration);
Algorithm algorithm = Algorithm.HMAC256(secret);
return JWT.create()
.withSubject(String.valueOf(userId))
.withClaim("openId", openId)
.withClaim("userType", userType)
.withIssuedAt(now)
.withExpiresAt(expiryDate)
.sign(algorithm);
}
// ... 其他实例方法 ...
}
调用方式
// 在 Service 中通过 @Autowired 注入
@Service
public class WxAuthService {
@Autowired
private JwtUtil jwtUtil; // 注入 Bean
public WxLoginVO login(...) {
// ...
String token = jwtUtil.createToken(...); // 调用实例方法
// ...
}
}
流程对比:两种设计下的 Token 生成之旅
时序图:依赖注入如何工作
状态图:配置的生命周期
类图与实体关系图
ERD (Entity Relationship Diagram, 实体关系图)
🧠 思维导图总结

虽然静态工具类在简单的场景下能快速解决问题,但从长远来看,拥抱框架、遵循“配置与代码分离”的原则,才是通往高质量、可维护软件的康庄大道。你的项目,正处于哪个境界呢?不妨检查一下吧!Happy coding! 🚀
155

被折叠的 条评论
为什么被折叠?



