netty学习05-handler介绍

1. Netty中Handler

从应用程序开发人员的角度来看,Netty的主要组件是ChannelHandler,而ChannelHandler包括入站和出站两种类型。

  • 数据入站,指的是数据从底层的Java NIO channel到Netty的Channel。
  • 数据出站,指的是通过Netty的Channel来操作底层的 Java NIO chanel。

1.1 inbound

入站(inbound)处理通常由底层Java NIO channel触发,主要事件如下:

1. 注册事件,当前channel注册到EventLoop(channelRegistered) 。当前channel从EventLoop取消注册(channelUnregistered)。

2. 连接建立事件 channelActive 和 连接关闭事件 channelInactive。

3. 读事件和读完成事件 channelRead、channelReadComplete。

4. 异常通知事件 exceptionCaught。

5. 用户自定义事件userEventTriggered。

6. Channel 可写状态变化事件 channelWritabilityChanged。

注意:每个方法都带了ChannelHandlerContext作为参数,具体作用是,在每个回调事件里面,处理完成之后,使用ChannelHandlerContext的fireChannelXXX方法来传递给下个ChannelHandler。

1.2 outbound

出站(inbound) Handler通常是Netty channel操作底层Java NIO channel,主要操作如下:

1. 端口绑定 bind。

2. 连接服务端 connect。

3. 写事件 write。

4. 刷新时间 flush。

5. 读事件 read。

6. 主动断开连接 disconnect。

7. 关闭 channel 事件 close。

注意:一些回调方法有ChannelPromise这个参数,我们可以调用它的addListener注册监听,当回调方法所对应的操作完成后,会触发这个监听。

1.3 handler、pipeline、handlerContext、channel的关系

在一个channel被创建时,会创建一个与之对应的DefaultChannelPipeline,然后可以通过pipeline的addLast将handler添加到pipeline的链表中,在添加的过程中会自动生成一个DefaultChannelHandlerContext对象来封装对应的Handler和channel。

因此,channel和pipeline是一一对应的,而一个pipeline中会有一个ChannelHandlerContext链表,每个ChannelHandlerContext是channel和handler的封装。

2. 自定义业务逻辑handler

public class MyServerHandler extends ChannelInboundHandlerAdapter {

    static ChannelGroup group=new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        System.out.println("MyServerHandler:"+ctx.channel().remoteAddress()+":"+msg);
//        ctx.writeAndFlush("123");
//        ctx.fireChannelRead(msg);//如果没有这个,则后面的入站handler将不会被执行
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        group.add(ctx.channel());
        System.out.println("接收到第"+group.size()+"个连接");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("接收到第"+group.size()+"个连接");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

public class MyServerHandler1 extends SimpleChannelInboundHandler<String> {

    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("MyServerHandler1:"+ctx.channel().remoteAddress()+":"+msg);
        ctx.fireChannelRead(msg);//如果没有这个,则后面的入站handler将不会被执行
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

自定义channelHandler,一般是继承SimpleChannelInboundHandler或者ChannelInboundHandlerAdapter,并重写相关方法。建议都用ChannelInboundHandlerAdapter。

SimpleChannelInboundHandler类的channelRead方法会在执行完后将buffer里的数据自动清空,而ChannelInboundHandlerAdapter类的channelRead方法只是调用了fire操作。

实现SimpleChannelInboundHandler并重写channelRead0方法注意事项:

不能在实现类中将客户端请求的参数回写到客户端,如下代码所示:

public class MyServerHandler1 extends SimpleChannelInboundHandler<String> {

    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("MyServerHandler1:"+ctx.channel().remoteAddress()+":"+msg);
        ctx.writeAndFlush(msg);//这行代码有风险,因为ctx的writeAndFlush是异步操作,有可能msg对应的buffer已经在这个方法执行完后被清空了
        ctx.fireChannelRead(msg);//如果没有这个,则后面的入站handler将不会被执行
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }
}

注意:如果实现的是SimpleChannelInboundHandler,则泛型类型如果和消息类型不一致时,不会进入channelRead0方法,而是进入下一个handler。

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值