服务器之家

服务器之家 > 正文

java 中 ChannelHandler的用法详解

时间:2020-12-11 14:54     来源/作者:追寻北极

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经常需要存储一些状态相关的信息。最简单和推荐的方法是使用成员变量:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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实例,来避免竞态的情况以至于未认证的客户端可以获得机密的信息:

?
1
2
3
4
5
6
7
8
// 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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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上:

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

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

原文链接:http://blog.csdn.net/joeyon1985/article/details/53424620

标签:

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
Intellij idea2020永久破解,亲测可用!!!
Intellij idea2020永久破解,亲测可用!!! 2020-07-29
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享
歪歪漫画vip账号共享2020_yy漫画免费账号密码共享 2020-04-07
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址
电视剧《琉璃》全集在线观看 琉璃美人煞1-59集免费观看地址 2020-08-12
最新idea2020注册码永久激活(激活到2100年)
最新idea2020注册码永久激活(激活到2100年) 2020-07-29
返回顶部