在实际项目中,接口往往包含多个功能点,不同客户需求不同,功能需要灵活组合。本文用最简单的语言介绍如何用责任链模式拆分接口功能,实现灵活的功能组合,并配备完整示例代码,方便中国程序员理解和使用。
一、什么是责任链模式?
责任链模式是一种设计模式,它把多个处理步骤(功能点)串成一条链,按顺序依次执行。每个处理步骤只关注自己的业务,处理完后把结果传给下一个,解耦了各个功能模块。
简单来说:
- 请求发送者只负责发起请求
- 多个处理者组成链条,依次处理请求
- 每个处理者只管自己的功能,处理完传给下一个
- 可以动态调整处理顺序,灵活应对不同需求
二、为什么用责任链模式拆分接口功能?
假设接口有十几个功能点,比如:
- 参数校验
- 系统配置检查
- 基础数据入库
- 核心数据入库
- 发送消息到消息中心
- 发送消息到MQ
不同客户需要不同功能组合。用责任链模式:
- 每个功能点做成独立模块(组件)
- 通过配置灵活调整执行顺序和功能开关
- 方便维护和扩展,不用改动整体代码
三、责任链模式核心结构
| 角色 | 作用说明 |
|---|---|
| 抽象处理者类 | 定义处理请求的抽象方法,所有功能模块继承它 |
| 具体处理者类 | 实现具体功能逻辑,如参数校验、数据入库等 |
| 上下文对象 | 用于各个处理者之间传递数据,保持业务解耦 |
| 责任链管理器 | 根据配置顺序,动态调用各个处理者 |
四、代码示例讲解
1. Maven依赖
<!-- 用于日志打印和JSON序列化 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
2. 业务上下文类 Contxt.java
用于在责任链中传递和修改数据,字段可根据业务需求自由扩展。
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Contxt {
private String name;
private String age;
private String address;
private String userId;
}
3. 抽象处理者类 ComponentAbstract.java
定义统一的处理接口和执行时间监控,所有功能模块继承它。
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
@Slf4j
public abstract class ComponentAbstract {
public void handlerRequest(Contxt contxt) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 执行具体业务逻辑
this.doHandler(contxt);
stopWatch.stop();
long cost = stopWatch.getTotalTimeMillis();
// 简单的执行时间日志分类
if (cost <= 10) {
log.info("执行 {} 方法,用时优秀: {} ms", getClass().getSimpleName(), cost);
} else if (cost <= 50) {
log.info("执行 {} 方法,用时一般: {} ms", getClass().getSimpleName(), cost);
} else if (cost <= 500) {
log.info("执行 {} 方法,用时延迟: {} ms", getClass().getSimpleName(), cost);
} else if (cost <= 1000) {
log.info("执行 {} 方法,用时缓慢: {} ms", getClass().getSimpleName(), cost);
} else {
log.info("执行 {} 方法,用时卡顿: {} ms", getClass().getSimpleName(), cost);
}
}
// 子类必须实现的业务处理方法
abstract public void doHandler(Contxt contxt);
}
4. 具体业务处理类示例(Test1.java)
继承抽象类,实现具体功能逻辑。用@Component注解注册到Spring容器,名称用于动态调用。
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("1")
@Slf4j
public class Test1 extends ComponentAbstract {
@Override
public void doHandler(Contxt contxt) {
log.info("Test1 执行,当前上下文:{}", JSON.toJSONString(contxt));
contxt.setName("Test1处理后");
contxt.setAge("30");
contxt.setAddress("北京");
contxt.setUserId("user1");
}
}
类似地,可以定义Test2、Test3、Test4等多个功能模块,分别实现不同业务。
5. Spring上下文工具类 AopProxyUtils.java
用于根据类名动态从Spring容器获取对应的组件实例,支持AOP代理。
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AopProxyUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
applicationContext = context;
}
public static <T> T getProxyBean(Class<T> clazz) {
if (applicationContext == null) {
throw new IllegalStateException("ApplicationContext未初始化");
}
return applicationContext.getBean(clazz);
}
public static Object getProxyBean(String name) {
if (applicationContext == null) {
throw new IllegalStateException("ApplicationContext未初始化");
}
return applicationContext.getBean(name);
}
}
6. 控制器示例 LiteFlowController.java
通过接口传入执行顺序参数,实现动态业务编排。
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/test")
@Slf4j
public class LiteFlowController {
@GetMapping("chain")
public String pattern(@RequestParam String index) {
Contxt contxt = Contxt.builder()
.age("初始化")
.address("初始化")
.name("初始化")
.userId("初始化")
.build();
String[] sequence = index.split(",");
for (String className : sequence) {
ComponentAbstract handler = (ComponentAbstract) AopProxyUtils.getProxyBean(className);
if (ObjectUtils.isNotEmpty(handler)) {
handler.handlerRequest(contxt);
} else {
log.warn("未找到组件: {}", className);
}
}
return JSON.toJSONString(contxt);
}
}
调用示例:
http://localhost:8082/test/chain?index=2,1,3,4
表示先执行Test2,再执行Test1、Test3、Test4,顺序灵活可控。
五、扩展说明
- 上下文类Contxt:可以根据业务需求添加更多字段,例如请求ID、用户信息、状态标志等,实现更复杂的数据传递。
- 执行顺序配置:实际项目中,执行顺序可以存数据库或Redis,启动时加载,方便动态调整。
- 性能监控:抽象类中集成了执行时间监控,帮助定位性能瓶颈。
- AOP支持:通过Spring容器获取Bean,保证事务、日志等AOP功能生效。
六、总结
责任链模式能有效拆分复杂接口的多功能点,提升代码的灵活性和可维护性。通过抽象处理者和上下文传递,实现业务模块解耦和动态编排。示例代码简单明了,适合中国开发者快速上手。
七、完整示例代码仓库结构建议
src/main/java/com/example/chain/
ComponentAbstract.java
Contxt.java
AopProxyUtils.java
Test1.java
Test2.java
Test3.java
Test4.java
LiteFlowController.java
通过以上介绍和示例,您可以轻松实现一个灵活、可扩展的责任链模式业务处理框架,满足不同客户的个性化需求。