当审批流需要支持动态配置,审批级别从3级扩展到10级时,重新设计变得必要。面对这个需求,我的第一反应是使用责任链模式——它似乎完美契合!然而,当我用递归方式实现责任链后,在审批级别调整到8级时,系统直接抛出了StackOverflowError。经过一天的折腾,我终于明白:递归实现责任链是一个美丽的陷阱,而使用List才是正道。
一、场景:审批流从3级扩展到10级
先说说业务场景。我们的审批流最初有3级:
- 主管审批:金额<1000元
- 经理审批:金额<10000元
- 总监审批:金额>=10000元
最初的if-else实现:
@Service
public class ApprovalService {
@Autowired
private SupervisorApprovalService supervisorService;
@Autowired
private ManagerApprovalService managerService;
@Autowired
private DirectorApprovalService directorService;
public ApprovalResult approve(ApprovalRequest request) {
BigDecimal amount = request.getAmount();
if (amount.compareTo(new BigDecimal("1000")) < 0) {
// 主管审批
return supervisorService.approve(request);
} else if (amount.compareTo(new BigDecimal("10000")) < 0) {
// 经理审批
return managerService.approve(request);
} else {
// 总监审批
return directorService.approve(request);
}
}
}
新需求:
- 审批级别可配置,从3级扩展到10级
- 每个级别的审批规则可动态调整
- 审批流程可跳过某些级别
我当时的想法:if-else肯定不行了,要用责任链模式!
二、第一次尝试:递归实现责任链(美丽的陷阱)
责任链模式的核心思想:
- 每个处理者知道下一个处理者
- 自己处理完后,交给下一个处理者
- 形成一条链
实现:
1. 审批处理器接口:
public interface ApprovalHandler {
/**
* 处理审批请求
* @param request 审批请求
* @return 审批结果
*/
ApprovalResult handle(ApprovalRequest request);
/**
* 设置下一个处理器
* @param next 下一个处理器
*/
void setNext(ApprovalHandler next);
/**
* 获取处理器级别
*/
String getLevel();
}
2. 主管审批处理器:
@Component
public class SupervisorApprovalHandler implements ApprovalHandler {
private ApprovalHandler next;
@Override
public ApprovalResult handle(ApprovalRequest request) {
// 1. 判断自己能否处理
if (canHandle(request)) {
// 2. 处理逻辑
ApprovalResult result = doApprove(request);
// 3. 如果通过,交给下一个处理器
if (result.isApproved() && next != null) {
return next.handle(request); // 递归调用
}
return result;
}
// 4. 如果不能处理,交给下一个
if (next != null) {
return next.handle(request); // 递归调用
}
return ApprovalResult.reject("无法处理");
}
private boolean canHandle(ApprovalRequest request) {
return request.getAmount().compareTo(new BigDecimal("1000")) < 0;
}
private ApprovalResult doApprove(ApprovalRequest request) {
// 主管审批逻辑
return ApprovalResult.approve("主管审批通过");
}
@Override
public void setNext(ApprovalHandler next) {
this.next = next;
}
@Override
public String getLevel() {
return "SUPERVISOR";
}
}
3. 经理审批处理器:
@Component
public class ManagerApprovalHandler implements ApprovalHandler {
private ApprovalHandler next;
@Override
public ApprovalResult handle(ApprovalRequest request) {
if (canHandle(request)) {
ApprovalResult result = doApprove(request);
if (result.isApproved() && next != null) {
return next.handle(request); // 递归调用
}
return result;
}
if (next != null) {
return next.handle(request); // 递归调用
}
return ApprovalResult.reject("无法处理");
}
private boolean canHandle(ApprovalRequest request) {
return request.getAmount().compareTo(new BigDecimal("10000")) < 0;
}
private ApprovalResult doApprove(ApprovalRequest request) {
// 经理审批逻辑
return ApprovalResult.approve("经理审批通过");
}
@Override
public void setNext(ApprovalHandler next) {
this.next = next;
}
@Override
public String getLevel() {
return "MANAGER";
}
}
4. 总监审批处理器:
@Component
public class DirectorApprovalHandler implements ApprovalHandler {
private ApprovalHandler next;
@Override
public ApprovalResult handle(ApprovalRequest request) {
// 总监是最后一级,不需要判断next
return doApprove(request);
}
private ApprovalResult doApprove(ApprovalRequest request) {
// 总监审批逻辑
return ApprovalResult.approve("总监审批通过");
}
@Override
public void setNext(ApprovalHandler next) {
// 总监是最后一级,不需要next
}
@Override
public String getLevel() {
return "DIRECTOR";
}
}
5. 构建责任链:
@Component
public class ApprovalChainBuilder {
@Autowired
private SupervisorApprovalHandler supervisorHandler;
@Autowired
private ManagerApprovalHandler managerHandler;
@Autowired
private DirectorApprovalHandler directorHandler;
public ApprovalHandler buildChain() {
// 构建链:主管 -> 经理 -> 总监
supervisorHandler.setNext(managerHandler);
managerHandler.setNext(directorHandler);
// directorHandler不需要setNext
return supervisorHandler;
}
}
6. 使用:
@Service
public class ApprovalService {
@Autowired
private ApprovalChainBuilder chainBuilder;
public ApprovalResult approve(ApprovalRequest request) {
ApprovalHandler chain = chainBuilder.buildChain();
return chain.handle(request);
}
}
优点:
- 解耦成功:每个处理器只关心自己的逻辑
- 可扩展:新增处理器,只需要实现接口,加入链中
- 灵活:可以动态调整链的顺序
三、踩坑:递归调用导致栈溢出
事故现象:
审批级别扩展到8级后,测试时报错:
java.lang.StackOverflowError
at com.example.approval.SupervisorApprovalHandler.handle(SupervisorApprovalHandler.java:25)
at com.example.approval.SupervisorApprovalHandler.handle(SupervisorApprovalHandler.java:30)
at com.example.approval.SupervisorApprovalHandler.handle(SupervisorApprovalHandler.java:30)
...重复1000次
原因分析:
// 审批级别:主管 -> 经理 -> 总监 -> 副总 -> 总经理 -> 董事会 -> 董事长 -> 集团
// 共8级
// 每个handle()方法调用next.handle(),是递归调用
// 递归深度 = 审批级别数 = 8
// JVM默认栈深度是1000左右,8级不会溢出
// 但如果在handle()里再调用其他方法,或者审批级别增加到20级,就会溢出
问题代码:
@Override
public ApprovalResult handle(ApprovalRequest request) {
if (canHandle(request)) {
ApprovalResult result = doApprove(request);
if (result.isApproved() && next != null) {
return next.handle(request); // 递归调用
}
return result;
}
if (next != null) {
return next.handle(request); // 递归调用
}
return ApprovalResult.reject("无法处理");
}
递归调用的问题:
- 每调用一次方法,栈帧增加一层
- 审批级别越多,栈帧越多
- 如果每个handle()里再调用其他方法,栈帧更多
- 最终可能导致StackOverflowError
四、第二次尝试:用List代替递归(正道)
解决方案:放弃递归,用循环遍历List
@Component
public class ApprovalService {
// Spring会自动注入所有ApprovalHandler
@Autowired
private List<ApprovalHandler> handlers;
public ApprovalResult approve(ApprovalRequest request) {
// 1. 根据审批级别排序
List<ApprovalHandler> sortedHandlers = handlers.stream()
.sorted(Comparator.comparing(ApprovalHandler::getOrder))
.collect(Collectors.toList());
// 2. 循环遍历,不是递归
ApprovalResult result = null;
for (ApprovalHandler handler : sortedHandlers) {
if (handler.canHandle(request)) {
result = handler.handle(request);
if (!result.isApproved()) {
// 如果某个环节拒绝,直接返回
return result;
}
}
}
return result != null ? result : ApprovalResult.reject("无法处理");
}
}
改造ApprovalHandler接口:
public interface ApprovalHandler {
/**
* 判断是否能处理
*/
boolean canHandle(ApprovalRequest request);
/**
* 处理审批
*/
ApprovalResult handle(ApprovalRequest request);
/**
* 获取执行顺序
*/
int getOrder();
}
具体实现:
@Component
public class SupervisorApprovalHandler implements ApprovalHandler {
@Override
public boolean canHandle(ApprovalRequest request) {
return request.getAmount().compareTo(new BigDecimal("1000")) < 0;
}
@Override
public ApprovalResult handle(ApprovalRequest request) {
// 主管审批逻辑
return ApprovalResult.approve("主管审批通过");
}
@Override
public int getOrder() {
return 1; // 第一个执行
}
}
@Component
public class ManagerApprovalHandler implements ApprovalHandler {
@Override
public boolean canHandle(ApprovalRequest request) {
return request.getAmount().compareTo(new BigDecimal("10000")) < 0;
}
@Override
public ApprovalResult handle(ApprovalRequest request) {
// 经理审批逻辑
return ApprovalResult.approve("经理审批通过");
}
@Override
public int getOrder() {
return 2; // 第二个执行
}
}
@Component
public class DirectorApprovalHandler implements ApprovalHandler {
@Override
public boolean canHandle(ApprovalRequest request) {
return true; // 总监处理所有
}
@Override
public ApprovalResult handle(ApprovalRequest request) {
// 总监审批逻辑
return ApprovalResult.approve("总监审批通过");
}
@Override
public int getOrder() {
return 3; // 第三个执行
}
}
优点:
- 没有递归,不会栈溢出
- 审批级别可以无限扩展
- 性能更好(循环比递归快)
- 代码更简洁
五、Spring的@Order注解:更优雅的控制顺序
Spring框架提供了@Order注解,可以更优雅地控制执行顺序,这是Spring框架中常用的功能之一。
@Component
@Order(1) // 第一个执行
public class SupervisorApprovalHandler implements ApprovalHandler {
// ...
}
@Component
@Order(2) // 第二个执行
public class ManagerApprovalHandler implements ApprovalHandler {
// ...
}
@Component
@Order(3) // 第三个执行
public class DirectorApprovalHandler implements ApprovalHandler {
// ...
}
使用:
@Component
public class ApprovalService {
@Autowired
private List<ApprovalHandler> handlers; // Spring会自动按@Order排序
public ApprovalResult approve(ApprovalRequest request) {
ApprovalResult result = null;
for (ApprovalHandler handler : handlers) {
if (handler.canHandle(request)) {
result = handler.handle(request);
if (!result.isApproved()) {
return result;
}
}
}
return result != null ? result : ApprovalResult.reject("无法处理");
}
}
六、责任链模式的适用场景
适合用责任链模式的场景:
- 审批流:多级审批,每级逻辑不同
- 过滤器:Servlet Filter、Spring Interceptor
- 权限校验:多个校验规则,按顺序执行
- 日志处理:多个日志处理器,按级别处理
- 异常处理:多个异常处理器,按类型处理
不适合用责任链模式的场景:
- 逻辑简单:只有1-2级,用if-else更直观
- 性能要求高:责任链有遍历开销
- 需要立即返回:责任链是顺序执行,不能并行
总结:责任链模式的使用原则
经过这次审批流改造,我对责任链模式的理解:
- 核心作用是解耦和顺序执行:每个处理器只关心自己的逻辑,不需要知道其他处理器。
- 避免递归实现:递归实现责任链是美丽的陷阱,容易栈溢出。用List + 循环更稳健。
- 控制执行顺序:用@Order注解或getOrder()方法控制顺序,别硬编码。
- 及时中断:如果某个处理器拒绝,应该立即中断,不要继续执行。
- 中小厂务实选择
- 简单场景:if-else
- 中等复杂:List + 循环
- 复杂场景:责任链模式 + Spring @Order
一句话总结:责任链模式很优雅,但递归是陷阱,List才是正道。