简介:
Pipeline是一条Netty管道流水线,一条管道需要很多Handler处理器来处理业务。Netty的业务处理器流水线ChannelPipeline是基于责任链设计模式(Chain of Responsibility)来设计的,内部是一个双向链表结构,能够支持动态地添加和删除Handler业务处理器。
模拟一下netty将Handler业务处理器加入到Pipeline流水线中,Context里包含流通的对象数据,
形成一个从头到尾的链式结构,只不过我实现的是单向,如下图
一、什么是责任链模式
责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
责任链模式通过将多个处理器(处理对象)以链式结构连接起来,使得请求沿着这条链传递,直到有一个处理器处理该请求为止。
责任链模式允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
二、责任链的结构
主要涉及到以下几个核心角色:
-
抽象处理者(Handler):
-
定义一个处理请求的接口,通常包含一个处理请求的方法(如
handleRequest
)和一个指向下一个处理者的引用(后继者)。
-
-
具体处理者(ConcreteHandler):
-
实现了抽象处理者接口,负责处理请求。如果能够处理该请求,则直接处理;否则,将请求传递给下一个处理者。
-
-
客户端(Client):
-
创建处理者对象,并将它们连接成一条责任链。通常,客户端只需要将请求发送给责任链的第一个处理者,无需关心请求的具体处理过程。
-
三、责任链的应用场景
责任链的应用场景主要包括:
-
多个对象可以处理同一个请求,但具体由哪个对象处理则在运行时动态决定。 这种情况下,责任链模式允许系统在不影响客户端的情况下动态地重新组织和分配责任。这意味着,请求的处理者可以在运行时根据具体情况灵活选择,提高了系统的灵活性和可扩展性。
-
在请求处理者不明确的情况下向多个对象中的一个提交一个请求。 责任链模式使得请求的发送者无需关心具体由哪个处理者来处理请求,只需将请求沿着链传递,直到有处理者能够处理为止。这有助于减少发送者与处理者之间的耦合,提高了系统的可维护性。
-
需要动态处理一组对象处理请求。 在责任链模式中,可以动态地指定一组对象来处理请求,或者添加新的处理者。这种灵活性使得系统能够适应不断变化的需求,而无需修改客户端代码。
简单来说,就是一个请求需要多种不同的处理方式来校验时,可以考虑责任链
四、责任链的代码实现
1、处理器上下文
/**
* 处理器上下文类
*/
public class DataCheckHandlerContext {
/**
* handler 所有责任链的合集
*/
private final List<AbstractDataCheckHandler> handlers;
/**
* 用于流转的对象
*/
private final Request request;
private int currentIndex = -1;
public DataCheckHandlerContext(List<AbstractDataCheckHandler> handlers, Request request) {
this.handlers = handlers;
this.request = request;
}
/**
* 执行下一个handler
*
*/
public void fireDataCheckHandler(){
currentIndex++;
if (currentIndex < handlers.size()){
handlers.get(currentIndex).fireDataCheckHandler(this);
}else {
System.out.println("End of pipeline, no more handlers to process the message.");
}
}
public void reset() {
currentIndex = -1;
}
public Request getRequest() {
return request;
}
}
2、抽象处理者类:
/**
* 定义抽象的父级稽核处理器
*/
public abstract class AbstractDataCheckHandler {
/**
* 该handle下面的nextHandler
*/
private AbstractDataCheckHandler nextHandler;
public void setNext(AbstractDataCheckHandler handler) {
this.nextHandler = handler;
}
public void fireDataCheckHandler(DataCheckHandlerContext ctx) {
Boolean handle = handle(ctx);
if (handle && nextHandler != null) {
nextHandler.fireDataCheckHandler(ctx);
}else {
System.out.println("End of pipeline, no more handlers to process the message.");
}
}
protected abstract Boolean handle(DataCheckHandlerContext ctx);
}
3、具体的处理者:
注:抽象类的实现类不能使用单一的注解@Resource或 @Autowired去实现bean的注入
可以使用构造器或set方法等其他方式注入
@Component
@Slf4j
public class DetailHandler extends AbstractDataCheckHandler {
private final Mapper mapper;
public PTrsCircuitRouteDetailHandler(Mapper mapper) {
this.mapper = mapper;
}
@Override
protected Boolean handle(DataCheckHandlerContext ctx) {
Request request = ctx.getRequest();
if(StringUtils.isEmpty(request)){
return false;
}
return true;
}
4、Pipeline:把链表统一起来
/**
* 搞一个类似于netty的Pipeline责任链
*/
public class DataCheckPipeline {
private final List<AbstractDataCheckHandler> handlers = new ArrayList<AbstractDataCheckHandler>();
public void addLastHandler(AbstractDataCheckHandler handler) {
synchronized (this){
if (!handlers.isEmpty()) {
handlers.get(handlers.size() - 1).setNext(handler);
}
handlers.add(handler);
}
}
public void addLastHandlers(AbstractDataCheckHandler... handlers) {
ObjectUtil.checkNotNull(handlers, "handlers");
AbstractDataCheckHandler[] var3 = handlers;
int var4 = handlers.length;
for(int var5 = 0; var5 < var4; ++var5) {
AbstractDataCheckHandler h = var3[var5];
if (h == null) {
break;
}
this.addLastHandler(h);
}
}
private DataCheckHandlerContext newContext( Request request){
return new DataCheckHandlerContext(handlers, request);
}
public void fireDataCheckHandler( Request request){
DataCheckHandlerContext dataCheckHandlerContext = newContext(request);
dataCheckHandlerContext.fireDataCheckHandler();
}
5、客户端类:
public static void main(String[] args) {
Request request = new Request();
DataCheckPipeline dataCheckPipeline = new DataCheckPipeline();
//可按顺序依次派发
dataCheckPipeline.addLastHandler(new DetailHandler(mapper));
dataCheckPipeline.addLastHandlers(new DetailHandler(mapper), new DetailHandler(mapper));
dataCheckPipeline.fireDataCheckHandler(request);
}
五、责任链模式的优缺点
优点
-
降低耦合度:发送者和接收者之间解耦。
-
简化对象:对象不需要知道链的结构。
-
灵活性:通过改变链的成员或顺序,动态地新增或删除责任。
-
易于扩展:增加新的请求处理类很方便。
缺点
-
请求未被处理:不能保证请求一定会被链中的某个处理者接收。
-
性能影响:可能影响系统性能,且调试困难,可能导致循环调用。
-
难以观察:运行时特征不明显,可能妨碍除错。