一、概要
上一篇把netty的基本思路介绍了一下,从这一篇文章开始我们将把netty的每一个组件分别进行拆解分析。针对核心的源码进行剖析。
本篇先重点分析下channel,netty的channel到底是一个什么样的概念。
二、channel是什么?
channel代表的一个连接,每个client请求会对应到具体的一个channel。
我们可以看到channel对应有几个重要的组件。
- channelHandler
- channelHandlerContext
- channelPipeline
三、ChannelHandlerContext
ChannelHandlerContext维护ChannelHandler的上下文内容。
什么是上下文?
- 维护ChannelHandler的一些状态信息的存储
-
ChannelHandler之间互相通讯的桥梁(通过ChannelHandlerContext,我们可以把上一个ChannelHandler的处理结果传递给下一个ChannelHandler )
ChannelHandlerContext类图
DefaultChannelHandlerContext
final class DefaultChannelHandlerContext extends AbstractChannelHandlerContext {
private final ChannelHandler handler;
DefaultChannelHandlerContext(
DefaultChannelPipeline pipeline, EventExecutor executor, String name, ChannelHandler handler) {
super(pipeline, executor, name, handler.getClass());
this.handler = handler;
}
@Override
public ChannelHandler handler() {
return handler;
}
}
channelHandler是业务逻辑的核心处理类。
DefaultChannelHandlerContext会关联到一个唯一的ChannelHandler。
AbstractChannelHandlerContext
abstract class AbstractChannelHandlerContext implements ChannelHandlerContext, ResourceLeakHint {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractChannelHandlerContext.class);
volatile AbstractChannelHandlerContext next;
volatile AbstractChannelHandlerContext prev;
我只截取了部分代码,可以看到AbstractChannelHandlerContext维护了一个双向链表,分别指向前后的两个结点。
接下来我们看next和prev这两个指针(虽然不是指针,但是作用跟C的指针的类似的)其实是通过DefaultChannelPipeline来进行维护的。
DefaultChannelPipeline
pipeline,顾名思义就是channel的管道。Pipeline把channelHandler和Context给连接起来。
/**
* The default {@link ChannelPipeline} implementation. It is usually created
* by a {@link Channel} implementation when the {@link Channel} is created.
*/
public class DefaultChannelPipeline implements ChannelPipeline {
...
...
//双向链表,维护了Context的首位指针
final AbstractChannelHandlerContext head;
final AbstractChannelHandlerContext tail;
//关联一个对应的channel
private final Channel channel;
...
//把context添加到链表的尾部
private void addLast0(AbstractChannelHandlerContext newCtx) {
AbstractChannelHandlerContext prev = tail.prev;
newCtx.prev = prev;
newCtx.next = tail;
prev.next = newCtx;
tail.prev = newCtx;
}
...
@Override
public final ChannelPipeline addLast(EventExecutorGroup group, String name, ChannelHandler handler) {
final AbstractChannelHandlerContext newCtx;
synchronized (this) {
checkMultiplicity(handler);
newCtx = newContext(group, filterName(name, handler), handler);
//添加到尾部
addLast0(newCtx);
// If the registered is false it means that the channel was not registered on an eventLoop yet.
// In this case we add the context to the pipeline and add a task that will call
// ChannelHandler.handlerAdded(...) once the channel is registered.
if (!registered) {
newCtx.setAddPending();
callHandlerCallbackLater(newCtx, true);
return this;
}
EventExecutor executor = newCtx.executor();
if (!executor.inEventLoop()) {
callHandlerAddedInEventLoop(newCtx, executor);
return this;
}
}
callHandlerAdded0(newCtx);
return this;
}
我们可以看到ChannelPipeline通过Context把ChannelHandler给连接起来。并且在添加Handler的时候会触发ChannelHandler.handlerAdded的方法。
ChannelHandler
ChannelHandler 有多个不同的实现类,最顶层的接口就是这个。
public interface ChannelHandler {
/**
* Gets called after the {@link ChannelHandler} was added to the actual context and it's ready to handle events.
*/
void handlerAdded(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called after the {@link ChannelHandler} was removed from the actual context and it doesn't handle events
* anymore.
*/
void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
/**
* Gets called if a {@link Throwable} was thrown.
*
* @deprecated if you want to handle this event you should implement {@link ChannelInboundHandler} and
* implement the method there.
*/
@Deprecated
void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
/**
* Indicates that the same instance of the annotated {@link ChannelHandler}
* can be added to one or more {@link ChannelPipeline}s multiple times
* without a race condition.
* <p>
* If this annotation is not specified, you have to create a new handler
* instance every time you add it to a pipeline because it has unshared
* state such as member variables.
* <p>
* This annotation is provided for documentation purpose, just like
* <a href="http://www.javaconcurrencyinpractice.com/annotations/doc/">the JCIP annotations</a>.
*/
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Sharable {
// no value
}
}
四、总结
本篇主要分析了一个Channel组成的核心组件有哪些,后面再对每一个组件做一一分析。