首页 > Web开发 > 详细

Netty引导流程解读

时间:2019-05-27 20:17:19      阅读:143      评论:0      收藏:0      [点我收藏+]

Channel的生命周期状态【状态转换将变为相应的事件,转发给ChannelPipeline中的ChannelHandler进行处理】
  ChannelUnregistered:Channel已经被创建,但还未注册到EventLoop
  ChannelRegistered:Channel已经被注册到了EventLoop
  ChannelActive:Channel处于活动状态(已经连接到它的远程节点)。它现在可以接收和发送数据了
  ChannelInactive:Channel没有连接到远程节点


ChannelHandler的生命周期【加入或者移除ChannelPipeline时调用这些方法,其有2个子类ChannelInboundHandler ChannelOutboundHandler】
  handlerAdded:当把ChannelHandler添加到ChannelPipeline中时被调用
  handlerRemoved:当从ChannelPipeline中移除ChannelHandler时被调用
  exceptionCaught:当处理过程中在ChannelPipeline中有错误产生时被调用


ChannelInboundHandler接口【入站】
  channelRegistered:当Channel已经注册到它的EventLoop并且能够处理I/O时被调用
  channelUnregistered:当Channel从它的EventLoop注销并且无法处理任何I/O时被调用
  channelActive:当Channel处于活动状态时被调用;Channel已经连接/绑定并且已经就绪
  channelInactive:当Channel离开活动状态并且不再连接它的远程节点时被调用
  channelReadComplete:当Channel上的一个读操作完成时被调用
  channelRead:当从Channel读取数据时被调用 【channelRead0是通过SimpleChannelInboundHandler的方法】
  ChannelWritability Changed:当Channel的可写状态发生改变时被调用。用户可以确保写操作不会完成得太快(以避免发生OutOfMemoryError)或者可以在Channel变为再次可写时恢复写入。可以通过调用Channel的isWritable()方法来检测Channel的可写性。与可写性相关的阈值可以通过Channel.config(). setWriteHighWaterMark()和    Channel.config().setWriteLowWater- Mark()方法来设置
  userEventTriggered:当ChannelnboundHandler.fireUserEventTriggered()方法被调用时被调用,因为一个POJO被传经了ChannelPipeline


ChannelOutboundHandler接口【出站 按需推迟操作或者事件(下载文件被暂停)】 channel->ChannelPipeline->ChannelOutboundHandler
  bind(ChannelHandlerContext,SocketAddress,ChannelPromise):当请求将Channel绑定到本地地址时被调用
  connect(ChannelHandlerContext,SocketAddress,SocketAddress,ChannelPromise):当请求将Channel连接到远程节点时被调用
  disconnect(ChannelHandlerContext,ChannelPromise):当请求将Channel从远程节点断开时被调用
  close(ChannelHandlerContext,ChannelPromise):当请求关闭Channel时被调用
  deregister(ChannelHandlerContext,ChannelPromise):当请求将Channel从它的EventLoop注销时被调用
  read(ChannelHandlerContext):当请求从Channel读取更多的数据时被调用
  flush(ChannelHandlerContext):当请求通过Channel将入队数据冲刷到远程节点时被调用
  write(ChannelHandlerContext,Object,ChannelPromise):当请求通过Channel将数据写到远程节点时被调用

资源泄漏:Netty提供了class ResourceLeakDetector 【java -Dio.netty.leakDetectionLevel=ADVANCED】

ChannelPipeline接口【每一个新创建的Channel都将会被分配一个新的ChannelPipeline】
ChannelPipeline保存了与Channel相关联的ChannelHandler;
ChannelPipeline可以根据需要,通过添加或者删除ChannelHandler来动态地修改;
ChannelPipeline有着丰富的API用以被调用,以响应入站和出站事件
ChannelHanlderContext【每加入一个Handler,就会绑定一个新建的ChannelHanlderContext】
可以通过调用ChannelHandlerContext上的pipeline()方法来获得被封闭的ChannelPipeline的引用。这使得运行时得以操作ChannelPipeline的ChannelHandler,我们可以利用这一点来实现一些复杂的设计。例如,你可以通过将ChannelHandler添加到ChannelPipeline中来实现动态的协议切换。
异常处理
ChannelHandler.exceptionCaught()的默认实现是简单地将当前异常转发给ChannelPipeline中的下一个ChannelHandler;
如果异常到达了ChannelPipeline的尾端,它将会被记录为未被处理;
要想定义自定义的处理逻辑,你需要重写exceptionCaught()方法。然后你需要决定是否需要将该异常传播出去。

技术分享图片

每个EventLoop都由一个Thread支撑
EventLoopGroup bossGroup = new NioEventLoopGroup();//默认创建的Thread数值为Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

  技术分享图片

EventLoopGroup oiobossGroup = new OioEventLoopGroup();

  技术分享图片

AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel>
B extends AbstractBootstarp<B,C> 子类型是父类型的一个参数类型,可以在运行时返回实例的引用以支持链式方式的调用Bootstrap 与 ServerBootstrap方法

  Bootstrap group(EventLoopGroup):设置用于处理Channel所有事件的EventLoopGroup
  Bootstrap channel(Class<? extends C>)Bootstrap channelFactory(ChannelFactory<? extends C>):channel()方法指定了Channel的实现类。如果该实现类没提供默认的构造函数[7],可以通过调用channel- Factory()方法来指定一个工厂类,它将会被bind()方法调用
<T> Bootstrap option(ChannelOption<T> option,T value):设置ChannelOption,其将被应用到每个新创建的Channel的ChannelConfig。这些选项将会通过bind()或者connect()方法设置到Channel,不管哪个先被调用。这个方法在Channel已经被创建后再调用将不会有任何的效果。支持的ChannelOption取决于使用的Channel类型。
<T> Bootstrap attr(Attribute<T> key, T value):指定新创建的Channel的属性值。这些属性值是通过bind()或者connect()方法设置到Channel的,具体取决于谁最先被调用。这个方法在Channel被创建后将不会有任何的效果。
  Bootstrap handler(ChannelHandler):设置将被添加到ChannelPipeline以接收事件通知的ChannelHandler
  Bootstrap clone():创建一个当前Bootstrap的克隆,其具有和原始的Bootstrap相同的设置信息
  Bootstrap remoteAddress(SocketAddress):设置远程地址。或者,也可以通过connect()方法来指定它
  ChannelFuture connect():连接到远程节点并返回一个ChannelFuture,其将会在连接操作完成后接收到通知
  ChannelFuture bind():绑定Channel并返回一个ChannelFuture,其将会在绑定操作完成后接收到通知,在那之后必须调用Channel. connect()方法来建立连接

 

EventLoopGroup bossGroup = new NioEventLoopGroup();//处理channel所有事件的group
ServerBootstrap serverBootstrap = new ServerBootstrap();//创建和连接新的服务端channel
serverBootstrap.group(bossGroup, workerGroup)//提供处理新链接channel事件的事件组
      .channel(NioServerSocketChannel.class)//指定所用的channel
      .childHandler(new ChannelInitializer<SocketChannel>() {//设置处理channel事件和数据的handler
         @Override
         public void initChannel(SocketChannel ch) throws Exception {

  

ServerBootstrap bootstrap = new ServerBootstrap();  // ← --  创建ServerBootstrap 以创建ServerSocketChannel,并绑定它
bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())// ← --  设置EventLoopGroup,其将提供用以处理Channel 事件的EventLoop
        .channel(NioServerSocketChannel.class)// ← --  指定要使用的Channel 实现
        .childHandler(// ← --  设置用于处理已被接受的子Channel 的I/O 和数据的ChannelInboundHandler
                new SimpleChannelInboundHandler<ByteBuf>() {
                    ChannelFuture connectFuture;
                    @Override
                    public void channelActive(ChannelHandlerContext ctx) throws Exception {
                        Bootstrap bootstrap = new Bootstrap();// ← --  创建一个Bootstrap类的实例以连接到远程主机
                        bootstrap.channel(NioSocketChannel.class).handler(//  ← --  指定Channel的实现
                                new SimpleChannelInboundHandler<ByteBuf>() {  // ← -- 为入站I/O 设置ChannelInboundHandler
                                    @Override
                                    protected void channelRead0(
                                            ChannelHandlerContext ctx, ByteBuf in)
                                            throws Exception {
                                        System.out.println("Received data");
                                    }
                                });
                        bootstrap.group(ctx.channel().eventLoop());// ← --  使用与分配给已被接受的子Channel 相同的EventLoop
                        connectFuture = bootstrap.connect(
                                new InetSocketAddress("www.123.com", 80)); //  ← --  连接到远程节点
                    }

                    @Override
                    protected void channelRead0(
                            ChannelHandlerContext channelHandlerContext,
                            ByteBuf byteBuf) throws Exception {
                        if (connectFuture.isDone()) {//当连接完成时,执行一些数据操作(如代理)
                        }
                    }
                });
ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));// ← --  通过配置好的ServerBootstrap绑定该Server-SocketChannel
future.addListener(new ChannelFutureListener() {
    @Override
    public void operationComplete(ChannelFuture channelFuture)
            throws Exception {
        if (channelFuture.isSuccess()) {
            System.out.println("Server bound");
        } else {
            System.err.println("Bind attempt failed");
            channelFuture.cause().printStackTrace();
        }
    }
});

  

 

Netty引导流程解读

原文:https://www.cnblogs.com/htkj/p/10932637.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!