Netty---ChannelHandler

一,概念

        能够被selector监控的IO事件有四种,分别是SelectionKey里面的 可读,可写 ,连接, 接收。四种。

        在NioEventLoop里面有selector对事件进行监听,然后dispatch(派发)给handler。Netty中handler分为两类,一种是通道入站处理器Inbound; 另外一种是通道出战处理器Outbound;

        两者都继承了ChannelHandler。

    举例:比如EventLoop查询到了OP_READ事件,那么它就发送给入站处理器:ChannelInboundHandler通道入站处理器,然后调用它的read()方法。从通道中读取数据。这两个接口有它的默认实现XXXAdapter,称为xxx处理适配器。实现了入站/出战的基本功能。我们自己的业务处理器只需要继承这两个处理适配器就可以了,不需要从0开始构建。

 

 在reactor反应器模式中,反应器将查询到的IO事件,分发到Handler业务处理器,由handler处理器完成IO操作和业务处理。整个处理包括:从通道读取数据包,数据包解码,业务处理,目标数据编码,把数据包写回通道。最后由通道发送。

    数据包解码,业务处理属于 入站处理器的工作,目标数据编码,把数据写回通道是 出站处理器的工作。

二,源码分析

1.ChannelHandler

    对于handler来说,它的继承关系图,相对来简单一点,但是由于handler是主要扩展和定制点,所以它的子类种类繁多,功能各异,系统的channelHandler主要分类如下:

    1.ChannelPipline的系统channelHandler,用于IO操作和对事件进行预处理,对用户不可见,主要包括HeadHandler,TailHandler。

    2.编解码ChannelHandler,包括ByteToMessageCodec,MessageToMessageDecoder等,这些编解码类本身又包括多种子类

    3.其他系统功能性ChannelHandler,包括流量整型handler,读写超时handler,日志handler等。

顶层接口源码:

public interface ChannelHandler {
//handler本身被添加道channelPipline的时候调用
    void handlerAdded(ChannelHandlerContext ctx) throws Exception;
//移除时调用
    void handlerRemoved(ChannelHandlerContext ctx) throws Exception;
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}

实现类:ChannelHandlerAdapter

    它并没有实现接口的两个add,remove方法,只是一个空的,交给子类重写。但是里面有一个重要的方法,用来提升性能的,减少线程间的竞争。

public abstract class ChannelHandlerAdapter implements ChannelHandler {
...
    public boolean isSharable() {
        Class<?> clazz = getClass();
        Map<Class<?>, Boolean> cache = InternalThreadLocalMap.get().handlerSharableCache();
        Boolean sharable = cache.get(clazz);
        if (sharable == null) {
            sharable = clazz.isAnnotationPresent(Sharable.class);
            cache.put(clazz, sharable);
        }
        return sharable;
    }...
}

2.实现类

2.1 ChannelInboundHandler

实现类,有两个常用的,

1.SimpleChannelInboundHandler

它的两个字段:

private final TypeParameterMatcher matcher; //类型参数匹配器
private final boolean autoRelease;  //是否自动解析

我们之所以选择handler直接继承这个类,就是因为可以自动进行匹配,然后对消息进行转换。

核心方法:ChannelRead()

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    boolean release = true;
    try {
        if (acceptInboundMessage(msg)) {
            @SuppressWarnings("unchecked")
            I imsg = (I) msg;   //通过范型,将得到的message,转换成指定pojo(也就是范型)
            channelRead0(ctx, imsg); //调用子类实现方法对 结果进行处理
        } else {
            release = false;
            ctx.fireChannelRead(msg);
        }
    } finally {
        if (autoRelease && release) {
            ReferenceCountUtil.release(msg);
        }
    }
}

2.ChannelInitializer

用来连接用户自定义的handler与pipline,

Channel在初始化的时候,调用pipline,添加handler,而我们的ChannelInitializer就会作为handler加入到pipline链路中,但是这里它的initChannel()方法又装了handler,所以这里先不要着急,在handler真正放入pipline中的时候,会调用handlerAdded()方法

public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    if (ctx.channel().isRegistered()) { //确保已经注册
        if (initChannel(ctx)) {  //这里会调用下面的方法
            removeState(ctx);
        }
    }
}

我们看它的initChannel()方法

private boolean initChannel(ChannelHandlerContext ctx) throws Exception {
    if (initMap.add(ctx)) { // 将context加入到集合中。
        try {
            initChannel((C) ctx.channel()); //再次初始化,这个方法,就是子类的方法,也就是我们手写的方法了。
        } ... finally {
    ChannelPipeline pipeline = ctx.pipeline();
    if (pipeline.context(this) != null) { //最后把自己从pipline中移除。
        pipeline.remove(this);
    }
}
}

所以Channelnitializer是作为pipline和Handler之间的桥梁,它最开始把自己加入进去了,最后又把自己删除了!

2.2 ChannelOutboundHandler

主要方法,和inbound完全不一样,

它主要是对消息进行response,回传响应,所以需要bind()地址,还要进行连接,等等操作。最后需要把消息写入到bytebuf中,通过channel传回。

而它的实现类ChannelOutboundHandlerAdapter,将所有方法,都调用了一遍参数context的同名方法,比如:

public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
    ctx.deregister(promise);
}

所以方法都是如此。

 

参考链接:https://www.jianshu.com/p/a9bcd89553f5

                 https://www.jianshu.com/p/96a50869b527

《netty权威指南》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值