欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java 中 ChannelHandler的用法详解

程序员文章站 2024-02-19 08:48:28
java 中 channelhandler的用法详解 前言: channelhandler处理一个i/o event或者拦截一个i/o操作,在它的channelpi...

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,每次创建一个新的实例。因为它有非共享的状态,比如:成员变量。

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