Netty 之 ChannelHandler,ChannelHandlerContext,ChannelPipeline

来源:互联网 发布:Linux 网络文件夹 编辑:程序博客网 时间:2024/05/22 08:06

本小节一起学习一下ChannelHandler,ChannelHandlerContext,ChannelPipeline这三个Netty常用的组件,不探究它们的底层源码,我们就简单的分析一下用法


首先先分析一下ChannelHandler,ChannelHandler是我们日常开发中使用最多的组件了,大概我们平时写的最多的组件就是Handler了,继承图如下



我们平时继承的最多的就是ChannelInboundHandlerAdapter和ChannelOutboundHandlerAdapter,这两个不是接口也不是抽象类,所以我们可以仅仅重写我们需要的方法,没有必须要实现的方法,当然我们也会使用SimpleChannelInboundHandler,这个类我们上个小节也稍微讲了它的优缺点,这里不赘述


ChannelHandler,ChannelHandlerContext,ChannelPipeline这三者的关系很特别,相辅相成,一个ChannelPipeline中可以有多个ChannelHandler实例,而每一个ChannelHandler实例与ChannelPipeline之间的桥梁就是ChannelHandlerContext实例,如图所示:

看图就知道,ChannelHandlerContext的重要性了,如果你获取到了ChannelHandlerContext的实例的话,你可以获取到你想要的一切,你可以根据ChannelHandlerContext执行ChannelHandler中的方法,我们举个例子来说,我们可以看下ChannelHandlerContext部分API:


这几个API都是使用比较频繁的,都是调用当前handler之后同一类型的channel中的某个方法,这里的同一类型指的是同一个方向,比如inbound调用inbound,outbound调用outbound类型的channel,一般来说,都是一个channel的ChannnelActive方法中调用fireChannelActive来触发调用下一个handler中的ChannelActive方法


我们举例来说,我们修改Helloworld版中的部分代码,在客户端中的channel中修改一下代码

首先我们修改一下bootstrap的启动类代码:

[html] view plain copy
  1. try {  
  2.             Bootstrap b = new Bootstrap();  
  3.             b.group(group)  
  4.              .channel(NioSocketChannel.class)  
  5.              .option(ChannelOption.TCP_NODELAY, true)  
  6.              .handler(new ChannelInitializer<SocketChannel>() {  
  7.                  @Override  
  8.                  public void initChannel(SocketChannel ch) throws Exception {  
  9.                      ChannelPipeline p = ch.pipeline();  
  10.                      p.addLast("decoder", new StringDecoder());  
  11.                      p.addLast("encoder", new StringEncoder());  
  12.                      p.addLast(new BaseClient1Handler());  
  13.                      p.addLast(new BaseClient2Handler());  
  14.                  }  
  15.              });  
  16.   
  17.             ChannelFuture future = b.connect(HOST, PORT).sync();  
  18.             future.channel().writeAndFlush("Hello Netty Server ,I am a common client");  
  19.             future.channel().closeFuture().sync();  
  20.         } finally {  
  21.             group.shutdownGracefully();  
  22.         }  
我们在channelhandler链中加了两个自定义的BaseClient1Handler和BaseClient2Handler的处理器

BaseClient1Handler的方法也很简单:

BaseClient1Handler.java

[java] view plain copy
  1. package com.lyncc.netty.component.channelhandler;  
  2.   
  3. import io.netty.channel.ChannelHandlerContext;  
  4. import io.netty.channel.ChannelInboundHandlerAdapter;  
  5.   
  6. /** 
  7.  *  
  8.  * @author bazingaLyncc 
  9.  * 描述:客户端的第一个自定义的inbound处理器 
  10.  * 时间  2016年5月3日 
  11.  */  
  12. public class BaseClient1Handler extends ChannelInboundHandlerAdapter{  
  13.       
  14.     @Override  
  15.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  16.         System.out.println("BaseClient1Handler channelActive");  
  17. //        ctx.fireChannelActive();  
  18.     }  
  19.       
  20.     @Override  
  21.     public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
  22.         System.out.println("BaseClient1Handler channelInactive");  
  23.     }  
  24.   
  25. }  
BaseClient2Handler.java

[java] view plain copy
  1. package com.lyncc.netty.component.channelhandler;  
  2.   
  3. import io.netty.channel.ChannelHandlerContext;  
  4. import io.netty.channel.ChannelInboundHandlerAdapter;  
  5.   
  6. /** 
  7.  *  
  8.  * @author bazingaLyncc 
  9.  * 描述:客户端的第二个自定义的inbound处理器 
  10.  * 时间  2016年5月3日 
  11.  */  
  12. public class BaseClient2Handler extends ChannelInboundHandlerAdapter{  
  13.       
  14.     @Override  
  15.     public void channelActive(ChannelHandlerContext ctx) throws Exception {  
  16.         System.out.println("BaseClient2Handler Active");  
  17.     }  
  18.       
  19.      
  20.   
  21. }  
其他的代码不修改的,我们先启动服务器端,然后启动客户端,你会发现控制台打印了:

不会打印BaseClient2Handler类中channelActive方法中的输出语句,如果你想要打印,你可以将BaseClient1Handler中的channelActive的ctx.fireChannelActive()注释去掉。重新运行:

也就是说如果一个channelPipeline中有多个channelHandler时,且这些channelHandler中有同样的方法时,例如这里的channelActive方法,只会调用处在第一个的channelHandler中的channelActive方法,如果你想要调用后续的channelHandler的同名的方法就需要调用以“fire”为开头的方法了,这样做很灵活


目前来说这样做的好处:

1)每一个handler只需要关注自己要处理的方法,如果你不关注channelActive方法时,你自定义的channelhandler就不需要重写channelActive方法

2)异常处理,如果 exceptionCaught方法每个handler都重写了,只需有一个类捕捉到然后做处理就可以了,不需要每个handler都处理一遍

3)灵活性。例如如下图所示:


如图所示在业务逻辑处理中,也许左侧第一个ChannelHandler根本不需要管理某个业务逻辑,但是从第二个ChannelHandler就需要关注处理某个业务需求了,那么就可以很灵活地从第二个ChannelHandler开始处理业务,不需要从channel中的第一个ChannelHandler开始处理,这样会使代码显得让人看不懂~


初步看懂的ChannelHandler,ChannelHandlerContext,ChannelPipeline之间的关系就是如上总结的


以上三点是我自己总结的,没看源码,有些也可能不对,欢迎拍砖,一起学习的过程,不保证全部对~

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 广州出租车丢了东西怎么办 广州的士丢了东西怎么办 网上找兼职被骗了怎么办 海信空调开不了机怎么办 海信空调遥控器开不了怎么办 学生遭套路贷反被仲裁怎么办 赏脸打错字尝脸怎么办 红掌的花变黑了怎么办 红掌花苞发黑了怎么办 水培植物腐根了怎么办 水培绿萝水发臭怎么办 水里养花根烂掉怎么办 桅子花叶子发黑怎么办 大株月季烂根怎么办 月季水浇多了烂根的怎么办 金桔盆栽烂根怎么办 盆栽的长寿果树烂根怎么办 家里的石榴烂根怎么办 山桔盆栽烂根怎么办 养的植物烂根怎么办 桅子花叶子长霉怎么办 紫薇花叶子干了怎么办 高层玻璃阳台往下看恐高怎么办 比熊放阳台叫怎么办 海员入职体检不合格怎么办 联币金融立案投资人怎么办 联币金融的投资怎么办 养老保险领了几个月就挂了怎么办 高铁餐吧乘务员东西卖不出去怎么办 铁路局如果查出有乙肝怎么办 在火车站丢了东西怎么办 在新乡火车站丢了东西怎么办 自己的行李忘到高铁安检怎么办 高铁二等座睡觉怎么办 空少岁数大了怎么办 美国留学生办欧洲签证怎么办 苏州小区不让装充电桩怎么办 饿了么运力不足怎么办 书法落款写偏了怎么办 辐射4运行不流畅怎么办 vgs币忘了映射怎么办