Netty-03:ChannelHandler学习笔记

基于netty 4.0官方文档
http://netty.io/4.0/api/index.html

Netty-ChannelHandler


1.简介

public interface ChannelHandler

负责处理或者拦截ChannelInboundInvoker 或者ChannelOutBoundInvoker 操作并将其传递到ChannelPipeline 的下一个handler .


2.上下文context
每个ChannelHandler netty都为它提供了一个ChannelHandlerContext 对象. ChannelHandler 通过这个context来与它所属的ChannelPipeline 交互. 通过这个context实例,ChannelHandler 可以把事件向pipeline 的上游或者下游传递, 来动态地修改pipeline 或者通过AttributeKeys来存储信息.


3.状态管理
ChannelHandler 通常需要存储一些状态相关的信息. 最简单的方法就是使用成员变量:

public interface Message {
     // your methods here
 }

 public class DataServerHandler extends SimpleChannelInboundHandler<Message> {

     private boolean loggedIn;

      @Override
     public void channelRead0(ChannelHandlerContext ctx, Message message) {
         Channel ch = e.getChannel();
         if (message instanceof LoginMessage) {
             authenticate((LoginMessage) message);
             loggedIn = true;
         } else (message instanceof GetDataMessage) {
             if (loggedIn) {
                 ch.write(fetchSecret((GetDataMessage) message));
             } else {
                 fail();
             }
         }
     }
     ...
 }

因为上述handler 的实例拥有一个只为一个连接服务的, 所以需要为每一个新的连接创建一个新的handler 实例, 以避免未获得认证的客户端获得机密的信息.

// Create a new handler instance per channel.
 // See ChannelInitializer.initChannel(Channel).
 public class DataServerInitializer extends ChannelInitializer<Channel> {
      @Override
     public void initChannel(Channel channel) {
         channel.pipeline().addLast("handler", new DataServerHandler());
     }
 }

*使用AttributeKeys
尽管推荐使用成员变量来存储handler 的状态信息, 但是因为某些原因你可能不想创建太多的handler 实例. 在这种情况下, 可以使用ChannelHandlerContext 提供的AttributeKeys :

public interface Message {
     // your methods here
 }

  @Sharable
 public class DataServerHandler extends SimpleChannelInboundHandler<Message> {
     private final AttributeKey<Boolean> auth =
           AttributeKey.valueOf("auth");

      @Override
     public void channelRead(ChannelHandlerContext ctx, Message message) {
         Attribute<Boolean> attr = ctx.attr(auth);
         Channel ch = ctx.channel();
         if (message instanceof LoginMessage) {
             authenticate((LoginMessage) o);
             attr.set(true);
         } else (message instanceof GetDataMessage) {
             if (Boolean.TRUE.equals(attr.get())) {
                 ch.write(fetchSecret((GetDataMessage) o));
             } else {
                 fail();
             }
         }
     }
     ...
 }

这样该handler 的状态就绑定到了ChannelHandlerContext 上, 所以就可以将相同的handler 实例添加到不同的pipeline 上:

 public class DataServerInitializer extends ChannelInitializer<Channel> {

     private static final DataServerHandler SHARED = new DataServerHandler();

      @Override
     public void initChannel(Channel channel) {
         channel.pipeline().addLast("handler", SHARED);
     }
 }

*@Sharable注解
添加了@Sharable 注解的handler 意味着该handler 的同一个实例可以多次被添加到一个或多个pipeline 中.
如果不标注@Sharable 注解, 那么在pipeline 中每次添加都需要创建一个新的实例.


4.成员方法

返回值类型方法和描述
voidexceptionCaught(ChannelHandlerContext, Throwable)
该方法已被弃用
voidhandlerAdded(ChannelHandlerContext ctx)
在handler被添加到context并且准备好处理事件时调用该方法
voidhandlerRemoved(ChannerlHandlerContext ctx)
handlercontext 移除的时候调用

5.子类
ChannelHandler 本身没有提供太多方法, 为了处理输入输出事件需要实现它的子类. 以下两种可能是最有帮助的:

  • ChannelInboundHandlerAdapter
  • ChannelOutboundHandlerAdapter

*ChannelInboundHandlerAdapter

// 继承关系
java.lang.Object
    io.netty.channel.ChannelHandlerAdapter
        io.netty.channel.ChannelInboundHandlerAdapter

public class ChannelInboundHandlerAdapter
    extends ChannelHandlerAdapter
    implements ChannelInboundHandler

ChannelInboundHandlerAdapter 中定义了一些事件方法, 可由pipeline 中调用ChannelHandlerContext的fire*()方法来将事件传递给下一个handler, 重写这些方法就可以实现对事件的处理.

返回值类型方法和描述
voidchannelRegistered(ChannelHandlerContext ctx) throws java.lang.Exception
Channel 绑定到EventLoop 时触发
voidchannelUnregistered(ChannelHandlerContext ctx)throws java.lang.Exception
Channel 解绑时触发
voidchannelActive(ChannelHandlerContext ctx) throws java.lang.Exception
Channel 激活时触发(即建建立了连接)
voidchannelInactive(ChannelHandlerContext ctx) throws java.lang.Exception
Channel 断开连接时触发
voidchannelRead(ChannelHandlerContext ctx, java.lang.Object msg) throws java.lang.Exception
Channel 接收到message时触发
voidchannelReadComplete(ChannelHandlerContext ctx) throws java.lang.Exception
voiduserEventTriggered(ChannelHandlerContext ctx, java.lang.Object evt) throws java.lang.Exception
Channel 接收到用户定义的事件时触发
voidchannelWritabilityChanged(ChannelHandlerContext ctx) throws java.lang.Exception
voidexceptionCaught(ChannelHandlerContext ctx, java.lang.Throwable cause) throws java.lang.Exception

*ChannelOutboundHandlerAdapter

// 继承关系
java.lang.Object
    io.netty.channel.ChannelHandlerAdapter
        io.netty.channel.ChannelOutboundHandlerAdapter

public class ChannelOutboundHandlerAdapter
    extends ChannelHandlerAdapter
    implements ChannelOutboundHandler

与上述类似 ChannelOutboundHandlerAdapter 也有一系列的事件方法:

返回值类型方法和描述
voidbind(ChannelHandlerContext ctx, java.net.SocketAddress localAddress, ChannelPromise promise)
voidconnect(ChannelHandlerContext ctx, java.net.SocketAddress remoteAddress, java.net.SocketAddress localAddress, ChannelPromise promise) throws java.lang.Exception
voiddisconnect(ChannelHandlerContext ctx, ChannelPromise promise) throws java.lang.Exception
voidclose(ChannelHandlerContext ctx, ChannelPromise promise) throws java.lang.Exception
voidderegister(ChannelHandlerContext ctx, ChannelPromise promise) throws java.lang.Exception
voidread(ChannelHandlerContext ctx) throws java.lang.Exception
voidwrite(ChannelHandlerContext ctx, java.lang.Object msg, ChannelPromise promise) throws java.lang.Exception
voidflush(ChannelHandlerContext ctx) throws java.lang.Exception
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值