本章开始分析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事件的:

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

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中:

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

  如果去掉@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 超时没有写数据断开连接。  

  

  

  

  

  

netty源码解解析(4.0)-16 ChannelHandler概览的更多相关文章

  1. netty源码解解析(4.0)-17 ChannelHandler: IdleStateHandler实现

    io.netty.handler.timeout.IdleStateHandler功能是监测Channel上read, write或者这两者的空闲状态.当Channel超过了指定的空闲时间时,这个Ha ...

  2. netty源码解解析(4.0)-18 ChannelHandler: codec--编解码框架

    编解码框架和一些常用的实现位于io.netty.handler.codec包中. 编解码框架包含两部分:Byte流和特定类型数据之间的编解码,也叫序列化和反序列化.不类型数据之间的转换. 下图是编解码 ...

  3. netty源码解解析(4.0)-20 ChannelHandler: 自己实现一个自定义协议的服务器和客户端

    本章不会直接分析Netty源码,而是通过使用Netty的能力实现一个自定义协议的服务器和客户端.通过这样的实践,可以更深刻地理解Netty的相关代码,同时可以了解,在设计实现自定义协议的过程中需要解决 ...

  4. netty源码解解析(4.0)-19 ChannelHandler: codec--常用编解码实现

    数据包编解码过程中主要的工作就是:在编码过程中进行序列化,在解码过程中从Byte流中分离出数据包然后反序列化.在MessageToByteEncoder中,已经解决了序列化之后的问题,ByteToMe ...

  5. netty源码解解析(4.0)-11 Channel NIO实现-概览

      结构设计 Channel的NIO实现位于io.netty.channel.nio包和io.netty.channel.socket.nio包中,其中io.netty.channel.nio是抽象实 ...

  6. netty源码解解析(4.0)-10 ChannelPipleline的默认实现--事件传递及处理

    事件触发.传递.处理是DefaultChannelPipleline实现的另一个核心能力.在前面在章节中粗略地讲过了事件的处理流程,本章将会详细地分析其中的所有关键细节.这些关键点包括: 事件触发接口 ...

  7. netty源码解解析(4.0)-15 Channel NIO实现:写数据

    写数据是NIO Channel实现的另一个比较复杂的功能.每一个channel都有一个outboundBuffer,这是一个输出缓冲区.当调用channel的write方法写数据时,这个数据被一系列C ...

  8. netty源码解解析(4.0)-14 Channel NIO实现:读取数据

     本章分析Nio Channel的数据读取功能的实现. Channel读取数据需要Channel和ChannelHandler配合使用,netty设计数据读取功能包括三个要素:Channel, Eve ...

  9. netty源码解解析(4.0)-12 Channel NIO实现:channel初始化

    创建一个channel实例,并把它register到eventLoopGroup中之后,这个channel然后处于inactive状态,仍然是不可用的.只有在bind或connect方法调用成功之后才 ...

随机推荐

  1. Tido 习题-二叉树-区间查询

    题目描述 食堂有N个打饭窗口,现在正到了午饭时间,每个窗口都排了很多的学生,而且每个窗口排队的人数在不断的变化.现在问你第i个窗口到第j个窗口一共有多少人在排队? 输入 输入的第一行是一个整数T,表示 ...

  2. java垃圾回收机制整理

    一.垃圾回收器和finalize() java垃圾回收器只负责回收无用对象占据的内存资源.但是如果你的对象不是通过 new 创建的(所有的new 对象都往堆中开辟资源,在一个地方,方便清理/管理资源) ...

  3. C盘内存杀手:IDEA缓存文件!

    软件虽然装在D盘,C盘仍然还有一个文件夹 里面有两个文件夹: config 目录是 IntelliJ IDEA 个性化化配置目录,或者说是整个 IDE 设置目录.也是我个人认为最重要的目录,没有之一, ...

  4. 【nginx】反向代理

    反向代理事项负载均衡 是什么:百度 版本 :tomcat8 x2 nginx 1.8.1 保证两台tomcat正常启动. 配置文件:D:\nginx-1.8.1\conf\nginx.conf ,红色 ...

  5. Linux服务器使用Docker部署.net Core项目

    发布ASP.NET Core项目 和普通的项目发布一样,将项目发布到目标文件夹中 构建Dockerfile文件 在目标文件根目录新建Dockerfile文件(没有后缀) FROM microsoft/ ...

  6. Linux 中 IDEA 不能调试(Debug)项目

    问题描述: can't debug project on idea linux. 在Linux 中, IDEA能运行项目,但是点击调试项目,弹出警告.警告内容如下: Required connecto ...

  7. 巧妙解决element-ui下拉框选项过多的问题

    1. 场景描述 不知道你有没有这样的经历,下拉框的选项很多,上万个选项甚至更多,这个时候如果全部把数据放到下拉框中渲染出来,浏览器会卡死,体验会特别不好 用人会说element-ui的select有一 ...

  8. 浅入深出Vue:路由

    路由的概念在计算机界中的历史大概可以追溯到OSI模型中的数据链路层与网络层中的定义.这里的定义大意是:在转发数据包时,根据数据包的目的地址进行寻址,从而将数据包发往指定的目的地. 在 Web开发中同样 ...

  9. MyBatis 核心配置综述之Executor

    目录 MyBatis四大组件之 Executor执行器 Executor的继承结构 Executor创建过程以及源码分析 Executor接口的主要方法 Executor 的现实抽象 上一篇我们对Sq ...

  10. .Net知识大全(个人整理)

    .Net知识大全 本章内容适用于对.NET有一定基础的或者是想通过本文章对.NET基础知识记不清楚的朋友,可以通过本文章进行回顾. 面试的时候可能也会遇到相应的题目,建议面试前进行回顾!!! 1.NE ...