java 中 ChannelHandler的用法详解

 更新时间:2017年08月06日 14:50:16   作者:追寻北极  
这篇文章主要介绍了java 中 ChannelHandler的用法详解的相关资料,ChannelHandler处理一个I/O event或者拦截一个I/O操作,需要的朋友可以参考下

java 中 ChannelHandler的用法详解

前言:

ChannelHandler处理一个I/O event或者拦截一个I/O操作,在它的ChannelPipeline中将其递交给相邻的下一个handler。

通过继承ChannelHandlerAdapter来代替

因为这个接口有许多的方法需要实现,你或许希望通过继承ChannelHandlerAdapter来代替。

context对象

一个ChannelHandler和一个ChannelHandlerContext对象一起被提供。一个ChannelHander通过一个context对象和其所属的那个ChannelPipeline进行交互。使用context对象,ChannelHandler可以向上或者向下传递events,动态地修改pipeline,或者存储与handler相关的信息(使用AttributeKeys)。

状态管理

一个ChannelHandler经常需要存储一些状态相关的信息。最简单和推荐的方法是使用成员变量:

public interface Message {
  // your methods here
}

public class DataServerHandler extends SimpleChannelInboundHandler<Message> {

  private boolean loggedIn;

  @Override
  protected void messageReceived(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实例创建一个新的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
  protected void messageReceived(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 注解

在上面使用AttributeKey的例子中,你应该已经注意到了@Sharable注解。

如果一个ChannelHandler被注解为@Sharable,那意味着你可以只创建一个handler实例,并把它添加到一个或多个ChannelPipeline中多次,并不用考虑竞态的情况。

如果这个注解没有指定,你就只能为每次需要添加到pipeline中的handler,每次创建一个新的实例。因为它有非共享的状态,比如:成员变量。

如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

相关文章

  • Spring Boot CLI安装教程

    Spring Boot CLI安装教程

    Spring Boot是一个命令行工具,用于使用Spring进行快速原型搭建。本文重点给大家介绍Spring Boot CLI安装教程,感兴趣的朋友参考下吧
    2017-08-08
  • java生成excel报表文件示例

    java生成excel报表文件示例

    本篇文章主要介绍了java生成excel报表文件示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • java如何读取resources目录和同级目录文件

    java如何读取resources目录和同级目录文件

    介绍了Java中读取resources目录和同级目录文件的方法,并讨论了在IDE和发布环境中可能遇到的问题,通过测试发现,执行目录可能会影响文件读取,建议在使用`user.dir`时注意jar包的运行目录问题
    2024-12-12
  • maven deploy时报错的解决方法

    maven deploy时报错的解决方法

    这篇文章主要介绍了maven deploy时报错的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • Java使用多线程批次查询大量数据(Callable返回数据)方式

    Java使用多线程批次查询大量数据(Callable返回数据)方式

    今天给大家分享Java使用多线程批次查询大量数据(Callable返回数据)方式,多线程有好几种方式,今天说的方式比较好,实现Callable<> 这种方式能返回查询的数据,加上Future异步获取方式,查询效率大大加快,感兴趣的朋友一起看看吧
    2023-11-11
  • SpringBoot整合EasyExcel实现大规模数据的并行导出与压缩下载

    SpringBoot整合EasyExcel实现大规模数据的并行导出与压缩下载

    在 Spring Boot 应用中,整合 EasyExcel 实现并行导出数据并进行 Zip 压缩下载可以极大地提高数据处理效率和用户体验,文中通过代码示例介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2024-10-10
  • java实现的小时钟示例分享

    java实现的小时钟示例分享

    这篇文章主要介绍了java实现的小时钟示例,需要的朋友可以参考下
    2014-02-02
  • MyBatis新增数据并返回主键值方式

    MyBatis新增数据并返回主键值方式

    这篇文章主要介绍了MyBatis新增数据并返回主键值,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Java启动Tomcat的实现步骤

    Java启动Tomcat的实现步骤

    本文主要介绍了Java启动Tomcat的实现步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Java实现滑动验证码的示例代码

    Java实现滑动验证码的示例代码

    这篇文章主要为大家介绍了如何用Java语言实现滑动验证码的生成,项目采用了springboot,maven等技术,感兴趣的小伙伴可以跟随小编学习一下
    2022-02-02

最新评论