zoukankan      html  css  js  c++  java
  • netty源码解析(4.0)-16 ChannelHandler概览

      本章开始分析ChannelHandler实现代码。ChannelHandler是netty为开发者提供的实现定制业务的主要接口,开发者在使用netty时,最主要的工作就是实现自己的ChannelHandler。ChannelHandler在设计上需要和ChannelPipeline配合共同实现pipeline的事件传递能力,这要求ChannelHandler需要实现一些固定的基本功能。由于这个原因,如果让用户自己完整地实现,会显得比较麻烦。为此netty实现类一系列的类来帮助开发者以简单的方式实现自己的ChannelHandler,而且只需要把注意力聚焦在自己业务和定制的部分上。在netty中,ChannelHandler不仅仅是几个简单的接口定义,而是一系列的实现,这些实现针对不同的问题,其中包括:

      单一功能性的Handler实现: 

        IP过滤,实现IP黑白名单功能。

        写日志。

        SSL实现。

        超时处理。

          编码和序列化格式的支持:

        base64

                gzip,snappy压缩算法

          protoBuf

        String

        自定义数据包格式。

      常见应用层协议:

        http/https(后面的版本还支持http2)

        haprox

    ChannelHandler体系结构

      上图上的所有接口的实现都位于io.netty.channel包中,其中,ChannelHandler是最顶层抽象的接口,ChannelInboundHandler是处理inbound事件的接口,ChannelOutboundHandler是处理outbound事件的接口。ChannelHandlerApapter是与I/O无关的抽象实现。ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter是最简单的实现,他们什么都没做,仅仅使用ChannelHandlerContext把事件传递到pipleline中下一个handler,如果你不清楚在正在处理事件之后如何传递事件,请参考这两个类中的代码。比如,ChannelInboundAdapter中是这样传递read事件的:

    1 @Override
    2 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    3         ctx.fireChannelRead(msg);
    4 }

    CombinedChannelDuplexhandler兼具ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter的能力。如果你想让一个Handler同时处理inbound和outbound事件,请继承这个类。

    ChannelHandler的共享和独占模式

      netty为ChannelHandler设计了两种模式,如果用ChannelHandler.Sharable修饰你的Handler, 那么这个Handler实例就是可共享的,否则它就是被某个Channel独占的。

    @ChannelHandler.Sharable
    public class MyHandler extends ChannelInboundHandler{
    }

      这个MyHandler的实例是可以被不同的Channel共享的。在初始化Channel的时候可以这加入到pipeline中:

    1 public class HandlerInitializer extends ChannelInitializer<SocketChanne>{
    2     private static MyHandler handler   = new MyHandler();
    3     
    4     @Override
    5     protected void initChannel(SocketChannel ch) throws Exception{
    6         ch.pipeline().addLast(handler);
    7     }
    8 }

      如果去掉@ChannelHandler.Sharable,它就是独占的,默认的都是独占。它可以这样用:

    public class HandlerInitializer extends ChannelInitializer<SocketChanne>{
         
         @Override
         protected void initChannel(SocketChannel ch) throws Exception{
             ch.pipeline().addLast(new MyHandler());
         }
    }

      ChannelHandlerAdapter的isSharable方法负责处理@ChannelHandler.Sharable:

    public boolean isSharable() {
            /**
             * Cache the result of {@link Sharable} annotation detection to workaround a condition. We use a
             * {@link ThreadLocal} and {@link WeakHashMap} to eliminate the volatile write/reads. Using different
             * {@link WeakHashMap} instances per {@link Thread} is good enough for us and the number of
             * {@link Thread}s are quite limited anyway.
             *
             * See <a href="https://github.com/netty/netty/issues/2289">#2289</a>.
             */
            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;
        }

      现在已经清楚了@ChannelHandler.Sharable影响和用法。那么问题来了,netty为什么要设计这样一个东西,它解决了什么问题呢?弄清这个问题之前,我们先来弄清楚ChannelHandler的作用。每个ChannelHandler实例都在Channel的pipeline上占据一个节点,每个节点带代表了事件处理流水线上的一道工序,具体每道工序是什么,由开发者自己定义和实现。总体来说,netty把工序分成两种类型: 有状态的和无状态的。有状态的就是独占的,无状态的是可以共享的。有状态和无状态这个两个概念太过于抽象。举个例子,http协议是一个基于TCP的应用层协议,实现这个协议的时候有一道工序是从tcp流中读到一个完整http数据报,tcp不保证每次read都刚好是一个完整的http数据报,很有可能是不完整的,这时候要把不完整的数据保存在缓冲区中, 下次read到数据之后追加到缓冲区,直到得到一个完整的http数据报。处理这道工序的Handler是有状态的,必须使用独占的Handler。

      一个Handler的实例是否可以共享,由它处理的工序决定的。即使netty没有设计这种独占/共享模式,开发者也应该可以把握好Handler的用法。

     常用的功能性Handler

      io.netty.handler包中是netty提供的常用的功能性的handler:

      io.netty.handler.ipfilter.RuleBasedIpFilter  使用IpFilterRule过过滤远程地址。

      io.netty.handler.ipfilter.UniqueIpFilter  一个地址只允许和服务器建立一个连接。

      io.netty.handler.logging.LoggingHandler 异步读/写日志。

      io.netty.handler.stream.ChunkedWriteHandler 异步读/写文件。

      io.netty.handler.timeout.IdleStateHandler  超时触发空闲状态事件。

      io.netty.handler.timeout.ReadTimeoutHandler 超时没有收到数据断开连接。

      io.netty.handler.timeout.WriteTimeoutHandler 超时没有写数据断开连接。  

      

      

      

      

      

  • 相关阅读:
    天梯赛5-12 愿天下有情人都是失散多年的兄妹 【dfs】
    poj2718 Smallest Difference【贪心】
    HDU problem 5635 LCP Array【思维】
    codeforces 782C Andryusha and Colored Balloons【构造】
    HDU 4278 Faulty Odometer【进制转换】
    codeforces B. The Meeting Place Cannot Be Changed【二分】
    POJ 3264 Balanced Lineup 【线段树】
    HDU 1850
    CodeForces-714C
    HDU Problem 1247 Hat's Words 【字典树】
  • 原文地址:https://www.cnblogs.com/brandonli/p/10612357.html
Copyright © 2011-2022 走看看