1. 什么是责任链模式?
顾名思义,通过将一个操作划分为不同的责任(职责、任务),通过任务执行先后顺序,将每个任务串联起来形成一个链路模式。调用方不需要关注每个任务的具体实现,每个任务之间互相解耦,只需要关注自身任务即可。
2. 为什么用责任链模式?
使用责任链模式,可以将业务解耦,实现高内聚低耦合,提高代码可读性,只需要关注每个任务自身,维护成本低。
3. 责任链模式怎么用?
- 定义责任链基类
public abstract class TaskHandler {
private List<TaskHandler> nexts;
public void setNexts(List<TaskHandler> nexts) {
this.nexts = nexts;
}
public List<TaskHandler> getNexts() {
return nexts;
}
public abstract void handleRequest(TaskContext contextData);
/**
* @description: 当前职责的下游处理器
**/
public void syncNextHandler(List<TaskHandler> nexts, TaskContext contextData){
if (ObjectUtils.isEmpty(nexts) || !contextData.isTaskStatus()) {
return;
}
for (TaskHandler next : nexts){
if(next == null){
continue;
}
next.handleRequest(contextData);
}
}
}
- 定义每个任务的具体实现,根据业务需求,拆解任务
@Slf4j
public class Task extends TaskHandler{
@Override
public void handleRequest(TaskContext contextData) {
try {
log.info("开始执行责任链");
System.out.println("开始执行责任链");
contextData.setTaskCurNum(contextData.getTaskCurNum() +1);
}catch (Exception e) {
contextData.setTaskStatus(false);
log.error("开始执行责任链:", e);
}
super.syncNextHandler(this.getNexts(), contextData);
}
}
@Slf4j
public class Task1 extends TaskHandler{
@Override
public void handleRequest(TaskContext contextData) {
try {
log.info("执行任务1:");
System.out.println("执行任务1");
contextData.setTaskCurNum(contextData.getTaskCurNum() +1);
}catch (Exception e) {
contextData.setTaskStatus(false);
log.error("执行任务1失败:", e);
}
super.syncNextHandler(this.getNexts(), contextData);
}
}
- 定义责任链管理类,组装责任链所有任务
public class TaskChainMgt {
private TaskHandler getTaskChain() {
TaskHandler task1_1 = new Task1_1();
TaskHandler task1_2 = new Task1_2();
TaskHandler task1 = new Task1();
task1.setNexts(Lists.newArrayList(task1_1, task1_2));
TaskHandler task2 = new Task2();
TaskHandler task = new Task();
task.setNexts(Lists.newArrayList(task1, task2));
return task;
}
// 启动责任链
public void startTaskChain(TaskContext taskContext) {
TaskHandler taskHandler = getTaskChain();
taskHandler.handleRequest(taskContext);
}
}
- 运行测试
@RestController
@Slf4j
@RequestMapping(value = "/taskChain")
public class TaskChainController {
@GetMapping("/startTask")
public void startTask() {
TaskChainMgt taskChainMgt = new TaskChainMgt();
TaskContext taskContext = new TaskContext();
taskContext.setTaskTotalNum(5);
taskChainMgt.startTaskChain(taskContext);
boolean taskStatus = calTaskStatus(taskContext);
if (taskStatus) {
log.info("责任链执行结束");
} else {
log.error("责任链调用失败");
}
}
/**
* @Description: 轮询监听责任链执行结果
**/
private boolean calTaskStatus(TaskContext taskContext) {
Long startTime = System.currentTimeMillis();
boolean taskStatus = false;
try {
do{
if (!taskContext.isTaskStatus()) {
log.error("责任链调度失败,上下文:{}", taskContext);
return false;
}
taskStatus = taskContext.getTaskCurNum() != taskContext.getTaskTotalNum();
if((System.currentTimeMillis() - startTime)/1000>15){
log.error("责任链调度失败", taskContext);
return false;
}
if(taskStatus){
Thread.sleep(500);
}
}while (taskStatus);
taskStatus = true;
} catch (Exception e) {
log.error("责任链异常!");
}
return taskStatus;
}
}
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.d.t.t.Task : 开始执行责任链
开始执行责任链
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.d.t.t.Task1 : 执行任务1:
执行任务1
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.d.t.t.Task1_1 : 执行任务1_1:
执行任务1下子任务1_1
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.d.t.t.Task1_2 : 执行任务1_2:
执行任务1下子任务1_2
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.d.t.t.Task2 : 执行任务2:
执行任务2
2023-08-11 18:05:49.759 INFO 45648 --- [nio-8080-exec-1] c.e.f.c.TaskChainController : 责任链执行结束
4. 扩展
如果任务下nexts子任务较多的情况下,可以使用线程池,多线程处理,提高责任链执行效率。
5. 总结
责任链模式设计思路主要通过设置nexts属性将所有任务串联起来形成一个链条,通过调用最顶层任务,每个任务执行完成后,获取当前任务的子任务(nexts),遍历执行每个子任务,子任务执行完成后,再执行子任务下的子任务…直到所有任务执行完毕。使用过程中可以使用全局上下文对象,用来在每个任务之间传递内容。使用轮询监听任务是否执行完毕。