Pipeline是一个由HandlerContext节点构成的双向环形链表,结构如下图,最前面是HeadContext,末尾是TailContext中间是用户自定义的HandlerContext节点
先来看pipLine的构造参数
/**
* channelPipLine的默认构造方法
* @param channel
*/
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
//创建TailContext
tail = new TailContext(this);
//创建HeadContext
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
可以看到pipline默认创建一个head和tail并且组成一个双向链表,而pipline的创建需要一个channel作为参数,实际上pipline是在channel里面创建的(即一个channel对应一个pipline)
pipline的添加节点方法
public final ChannelPipeline addLast(ChannelHandler handler) {
return addLast(null, handler);
}
最终调用到
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
//检查handler是否重复添加
checkMultiplicity(handler);
//创建pipLine节点
newCtx = newContext(group, filterName(name, handler), handler);
//添加节点操作
addLast0(newCtx);
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
//判断当前线程是否是NioEventLoop运行线程
if (!executor.inEventLoop()) {
newCtx.setAddPending();
executor.execute(new Runnable() {
@Override
public void run() {
//调用hander的add方法
callHandlerAdded0(newCtx);
}
});
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
- 检查handler是否重复添加
- 创建pipLine节点
- 添加节点操作
- 调用hander的add方法
io.netty.channel.DefaultChannelPipeline#checkMultiplicity
private static void checkMultiplicity(ChannelHandler handler) {
if (handler instanceof ChannelHandlerAdapter) {
ChannelHandlerAdapter h = (ChannelHandlerAdapter) handler;
/**
* 如果handler没有@Sharable注解修饰
* 并且被添加过了,抛出异常
*/
if (!h.isSharable() && h.added) {
throw new ChannelPipelineException(
h.getClass().getName() +
" is not a @Sharable handler, so can't be added or removed multiple times.");
}
h.added = true;
}
}
对于一个adapter如果我们想要把它添加到多个pipline中去,可以加一个@Sharable注解修饰,负责会抛异常
io.netty.channel.DefaultChannelPipeline#newContext
private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler);
}
private String filterName(String name, ChannelHandler handler) {
if (name == null) {
//根据handler生成一个对应的name
return generateName(handler);
}
//检查name是否重复
checkDuplicateName(name);
return name;
}
io.netty.channel.DefaultChannelPipeline#checkDuplicateName
private void checkDuplicateName(String name) {
if (context0(name) != null) {
throw new IllegalArgumentException("Duplicate handler name: " + name);
}
}
/**
* 遍历head->....->tail节点name 看是否name重复
* @param name
* @return
*/
private AbstractChannelHandlerContext context0(String name) {
AbstractChannelHandlerContext context = head.next;
while (context != tail) {
if (context.name().equals(name)) {
return context;
}
context = context.next;
}
return null;
}
io.netty.channel.DefaultChannelPipeline#addLast0
//把创建的新节点添加到pipLine尾部
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
基本的链表操作,对链表操作熟悉的同学很容易理解
io.netty.channel.DefaultChannelPipeline#callHandlerAdded0
private void callHandlerAdded0(final AbstractChannelHandlerContext ctx) {
try {
ctx.setAddComplete();
//调用handler的handlerAdded方法
/**
* p.addLast(new ChannelInitializer<Channel>() {
* 会调用ChannelInitializer的handlerAdded(ctx)方法
*/
ctx.handler().handlerAdded(ctx);
} catch (Throwable t) {
......
}
添加完成之后修改节点的状态,并且调用对应handler的handlerAdded方法,用户可以在这个方法里面进行操作,或者把事件往下个节点传递
再看DefaultChannelHandlerContext节点
private final ChannelHandler handler;
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, isInbound(handler), isOutbound(handler));
if (handler == null) {
throw new NullPointerException("handler");
}
this.handler = handler;
}
就是一个保存了handler的数据结构,连接上一个和下一个节点
那么我们来思考一个问题客户端channel在连接到服务端channel之后是是怎么构建pipline,并且给pipline装配handlerContext节点
还记得前几篇我们说过,服务端channel在accept事件到来之后,
/**
* 读事件和 accept事件都会经过这里,但是拿到的unsafe对象不同 所以后续执行的read操作也不一样
* NioServerChannel进行accept操作
* NioChannel进行read操作
*/
if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) {
unsafe.read();
}
接着调用io.netty.channel.nio.AbstractNioMessageChannel.NioMessageUnsafe#read
@Override
public void read() {
assert eventLoop().inEventLoop();
final ChannelConfig config = config();
//拿到channel处理的pipline
final ChannelPipeline pipeline = pipeline();
final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();
allocHandle.reset(config);
boolean closed = false;
Throwable exception = null;
try {
try {
do {
//readBuf是一个集合 来保存accept出的channel
//具体read操作
int localRead = doReadMessages(readBuf);
if (localRead == 0) {
break;
}
if (localRead < 0) {
closed = true;
break;
}
allocHandle.incMessagesRead(localRead);
} while (allocHandle.continueReading());
} catch (Throwable t) {
exception = t;
}
int size = readBuf.size();
for (int i = 0; i < size; i ++) {
readPending = false;
//调用pipline的read方法通知事件
pipeline.fireChannelRead(readBuf.get(i));
}
//清除readBuf集合
readBuf.clear();
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
if (exception != null) {
closed = closeOnReadError(exception);
pipeline.fireExceptionCaught(exception);
}
if (closed) {
inputShutdown = true;
if (isOpen()) {
close(voidPromise());
}
}
} finally {
.....
if (!readPending && !config.isAutoRead()) {
removeReadOp();
}
}
}
}
调用pipeline.fireChannelRead(readBuf.get(i));来通知事件,最后从headcontext走到服务端启动的时候的添加的一个handler#ServerBootstrapAcceptor
@Override
@SuppressWarnings("unchecked")
public void channelRead(ChannelHandlerContext ctx, Object msg) {
//msg 新连接进来会传播事件 传递进来的channel对象
final Channel child = (Channel) msg;
//取出来新连接的pipLine 把Server端配置的handler添加进去
child.pipeline().addLast(childHandler);
setChannelOptions(child, childOptions, logger);
for (Entry<AttributeKey<?>, Object> e: childAttrs) {
child.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());
}
try {
//childGroup其实就是worker NioEventLoopGroup,去注册客户端的channel对象
childGroup.register(child).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if (!future.isSuccess()) {
forceClose(child, future.cause());
}
}
});
} catch (Throwable t) {
forceClose(child, t);
}
}
在这里会完成客户端channel中pipline添加处理器节点,而这个节点正是服务启动时设置给ServerBootstrap的
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc()));
}
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
那么我们知道每个客户端到来都会把这个handler添加到pipline中去,在pipline中有个重复添加的校验代码,ChannelInitializer是如何通过校验的呢?答案肯定是@Sharable
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
另一个就是pipline是什么时候创建的,还有服务端accept的客户端是java原生的channel,在哪完成的包装成netty自己的NioSocketChannel
io.netty.channel.nio.AbstractNioMessageChannel#doReadMessages
@Override
protected int doReadMessages(List<Object> buf) throws Exception {
//拿到新连接的channel
SocketChannel ch = SocketUtils.accept(javaChannel());
try {
if (ch != null) {
//添加到集合中去
buf.add(new NioSocketChannel(this, ch));
return 1;
}
new NioSocketChannel(this, ch)
就是在这一步完成的原生channel到netty NioSocketChannel的包装
再看NioSocketChannel构造方法
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
protected DefaultChannelPipeline newChannelPipeline() {
return new DefaultChannelPipeline(this);
}
看到这里是不是很清晰了,netty的设计思想层层递进,级级抽取