Netty-12-channelHandler热拔插

前面的代码中,我们的客户端登录之后,存了一个标记,表示当前的channel是已登录的状态,然后每次发现系的时候都需要去验证一次用户是否登录,代码如下:
image

这里我们也可以在服务端加一个handler去验证用户是否登录

登录验证handler

新建一个handler,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class AuthHandler extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!LoginUtil.hasLogin(ctx.channel())) {
ctx.channel().close();
} else {
super.channelRead(ctx, msg);
}
}

}

这里这个类继承自ChannelInboundHandlerAdapter,然后重写了channelRead()方法,也就是说,这个handler能处理所有类型的数据包

在这个channelRead()中,判断客户端是否登录,没有登录的话就直接关闭连接(实际生产环境可能逻辑要复杂些),如果登录了的话就将数据传给以一个handler去处理

然后再NettyServer中把这个handler加进去,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel ch) {
log.info("取出childAttr属性:{}", ch.attr(CommonConfig.CLIENT_KEY).get());

ch.pipeline()
.addLast(new Spliter())
.addLast(new PacketDecoder())
.addLast(new LoginRequestHandler())
.addLast(new AuthHandler())
.addLast(new MessageRequestHandler())
.addLast(new PacketEncoder());
}
});

这样MessageRequestHandler以及后面的handler都已经经过了AuthHandler的过滤,后续所有的handler都不用担心身份认证这个问题

热拔插

这里会有一个问题,就是客户端登录之后每次发送消息都会经过这个验证,其实只要客户端的连接未断开,客户端只要登录成功过,就不需要再去校验了,也就是说,我们只在第一次消息发过来的时候判断一下就好了, 这里就可以使用 pipeline 的热插拔机制

handler 其实可以看做是一段功能相对聚合的逻辑,然后通过 pipeline 把这些一个个小的逻辑聚合起来,串起一个功能完整的逻辑链.既然可以把逻辑串起来,也可以做到动态删除一个或多个逻辑

修改AuthHandler,修改后如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Slf4j
public class AuthHandler extends ChannelInboundHandlerAdapter {

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (!LoginUtil.hasLogin(ctx.channel())) {
ctx.channel().close();
} else {
ctx.pipeline().remove(this);
super.channelRead(ctx, msg);
}
}

@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
if (LoginUtil.hasLogin(ctx.channel())) {
log.info("当前连接登录验证完毕,无需再次验证, AuthHandler 被移除");
} else {
log.info("无登录验证,强制关闭连接!");
}
}
}

就是权限验证通过之后,就把自己移除,这里的remove(this)就指的是移除AuthHandler, 移除之后,后续的数据过来服务端就不会再校验是否登录了

然后还重写了handlerRemoved(),就是handler被移除的时候的回调,打印信息

分别启动服务端客户端看一下控制台输出

客户端:
image

服务端:
image

完整代码已上传github,传送门