这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战
前言
首先,我们要明白 Channel、ChannelHandler、ChannelPipe 这几个关键组件的关系。
Channel 就跟 BIO 中流(Stream) 一样是用来传输数据的,每一个客户端都会有一个 Channel;而每个 Channel 都包含了一个管道 ChannelPipeline;ChannelPipeline 提供了 ChannelHandler 的容器,可以理解成一个双向链表 -- 责任链模式。
pipeline职责连
为请求创建一个处理对象的链, 责任链模式使用的场景比较多比如我们熟悉的sential核心的规则处理, 我们平常业务处理比如营销中各种营销规则的优先级等,都可以采取这种责任链的模式。
Channel源码分析
Channel主要继承关系图
服务端 NioServerSocketChannel 类的继承关系图
客户端 NioSocketChannel
AbstractChannel
AbstractChannel内部有一个pipeline属性,Netty在对Channel进行初始化的时候将该属性初始化为DefaultChannelPipeline的实例
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
AbstractChannel#newChannelPipeline
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
TailContext , HeadContext 这个就是我们上面说的责任链头尾指针
* I/O Request
* via {@link Channel} or
* {@link ChannelHandlerContext}
* |
* +---------------------------------------------------+---------------+
* | ChannelPipeline | |
* | |/ |
* | +---------------------+ +-----------+----------+ |
* | | Inbound Handler N | | Outbound Handler 1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | |/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler N-1 | | Outbound Handler 2 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ . |
* | . . |
* | ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
* | [ method call] [method call] |
* | . . |
* | . |/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 2 | | Outbound Handler M-1 | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* | | |/ |
* | +----------+----------+ +-----------+----------+ |
* | | Inbound Handler 1 | | Outbound Handler M | |
* | +----------+----------+ +-----------+----------+ |
* | /|\ | |
* +---------------+-----------------------------------+---------------+
* | |/
* +---------------+-----------------------------------+---------------+
* | | | |
* | [ Socket.read() ] [ Socket.write() ] |
* | |
* | Netty Internal I/O Threads (Transport Implementation) |
* +-------------------------------------------------------------------+
inbound事件的流行是从下至上, 而outbound刚好相反,是从上到下。同时注释中列出了引发inbound事件和outbound事件传播的方法:
* <li>Inbound event propagation methods:
* <ul>
* <li>{@link ChannelHandlerContext#fireChannelRegistered()}</li>
* <li>{@link ChannelHandlerContext#fireChannelActive()}</li>
* <li>{@link ChannelHandlerContext#fireChannelRead(Object)}</li>
* <li>{@link ChannelHandlerContext#fireChannelReadComplete()}</li>
* <li>{@link ChannelHandlerContext#fireExceptionCaught(Throwable)}</li>
* <li>{@link ChannelHandlerContext#fireUserEventTriggered(Object)}</li>
* <li>{@link ChannelHandlerContext#fireChannelWritabilityChanged()}</li>
* <li>{@link ChannelHandlerContext#fireChannelInactive()}</li>
* <li>{@link ChannelHandlerContext#fireChannelUnregistered()}</li>
* </ul>
* </li>
* <li>Outbound event propagation methods:
* <ul>
* <li>{@link ChannelHandlerContext#bind(SocketAddress, ChannelPromise)}</li>
* <li>{@link ChannelHandlerContext#connect(SocketAddress, SocketAddress, ChannelPromise)}</li>
* <li>{@link ChannelHandlerContext#write(Object, ChannelPromise)}</li>
* <li>{@link ChannelHandlerContext#flush()}</li>
* <li>{@link ChannelHandlerContext#read()}</li>
* <li>{@link ChannelHandlerContext#disconnect(ChannelPromise)}</li>
* <li>{@link ChannelHandlerContext#close(ChannelPromise)}</li>
* <li>{@link ChannelHandlerContext#deregister(ChannelPromise)}</li>
* </ul>
* </li>
业务代码中责任链模式应用
责任链框架
public interface SlotChainBuilder<T> {
/**
* 构造器
* @return
*/
T build();
}
public interface ProcessorSlot<T> {
/**
* 前置处理方法
*/
void process(T param);
/**
* 触发下一个
* @param param
*/
void fireProcess(T param);
}
public abstract class ProcessorSlotChain<T> extends AbstractLinkedProcessorSlot<T> {
/**
* 添加到下一个触发节点
* @param processorSlot
*/
public abstract void addLast(AbstractLinkedProcessorSlot<T> processorSlot);
}
public class DefaultProcessorSlotChain<T> extends ProcessorSlotChain<T> {
//初始化头检点
AbstractLinkedProcessorSlot<T> first = new AbstractLinkedProcessorSlot<T>() {
@Override
public void processHandler(T param) {
//不做处理
}
};
AbstractLinkedProcessorSlot<T> end = first;
@Override
public void processHandler(T param) {
//初始化头节点
setNext(first);
}
@Override
public void addLast(AbstractLinkedProcessorSlot<T> processorSlot) {
//设置下一个节点
end.setNext(processorSlot);
//指针就指向下一个节点
end = processorSlot;
}
}
public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {
/**
* 设置链的下一个触发的组件
*/
private AbstractLinkedProcessorSlot<T> next = null;
@Override
public void fireProcess(T param) {
if(next != null){
//触发下一个节点执行
next.process(param);
}
}
public AbstractLinkedProcessorSlot<T> getNext() {
return next;
}
public void setNext(AbstractLinkedProcessorSlot<T> next) {
this.next = next;
}
@Override
public void process(T param) {
processHandler(param);
//触发下一个节点进行
fireProcess(param);
}
/**
* 定义钩子,是业务逻辑实际处理的实现
* @param param
*/
public abstract void processHandler(T param);
}
业务builder和节点
CheckerSlotChainBuilder
@Component
public class CheckerSlotChainBuilder implements SlotChainBuilder<ProcessorSlotChain> {
@Resource
private RepeatMobileCheckerSlot repeatMobileCheckerSlot;
@Resource
private TinyUrlValidatorSlot tinyUrlValidatorSlot;
@Override
public ProcessorSlotChain build() {
ProcessorSlotChain chain = new DefaultProcessorSlotChain();
chain.addLast(tinyUrlValidatorSlot);
chain.addLast(repeatMobileCheckerSlot);
return chain;
}
}
@Component
@Slf4j
public class RepeatMobileCheckerSlot extends AbstractLinkedProcessorSlot<SmsSendContext> {
@Override
public void processHandler(SmsSendContext param) {
log.info("重复手机号码校验:任务ID:{}", param.getTaskId());
}
}
@Component
@Slf4j
public class TinyUrlValidatorSlot extends AbstractLinkedProcessorSlot<SmsSendContext> {
@Override
public void processHandler(SmsSendContext param) {
log.info("校验短信群发任务中短链接的有效性,url:{}", param.getUrl());
}
}