第 8 章 引导

  1. 引导类的层次结构包括一个抽象的父类和两个具体的引导子类,服务器致力于使用一个父 Channel 来接受来自客户端的连接,并创建子 Channel 以用于它们之间的通信;而客户端将最可能只需要一个单独的、没有父 Channel 的 Channel 来用于所有的网络交互;Cloneable便于创建相同配置的引导类的浅拷贝


    第 8 章 引导_第1张图片
    image.png
  2. 子类型 B 是其父类型的一个类型参数,可以返回运行时的实例的引用以支持方法的链式调用
    public abstract class AbstractBootstrap ,C extends Channel>
  3. ServerBootstrap可分别设置ServerChannel和子Channeloptionattr,而Bootstrap则只创建一个Channel
    第 8 章 引导_第2张图片
    image.png
  4. 可以从Channel引导客户端,简单的例子就是在服务端连接建立后,再作为客户端去连接其他服务(如数据库等)
    第 8 章 引导_第3张图片
    image.png
    public class BootstrapSharingEventLoopGroup {
            public void bootstrap() {
                ServerBootstrap bootstrap = new ServerBootstrap();
                bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())
                    .channel(NioServerSocketChannel.class)
                    .childHandler(
                        new SimpleChannelInboundHandler() {
                            ChannelFuture connectFuture;
                            @Override
                            public void channelActive(ChannelHandlerContext ctx)
                                throws Exception {
                                // 作为客户端连接其他服务
                                Bootstrap bootstrap = new Bootstrap();
                                bootstrap.channel(NioSocketChannel.class).handler(
                                    new SimpleChannelInboundHandler() {
                                        @Override
                                        protected void channelRead0(
                                            ChannelHandlerContext ctx, ByteBuf in)
                                            throws Exception {
                                            System.out.println("Received data");
                                        }
                                    });
                                // 复用 EventLoop
                                bootstrap.group(ctx.channel().eventLoop());
                                connectFuture = bootstrap.connect(
                                    new InetSocketAddress("www.manning.com", 80));
                            }
        
                            @Override
                            protected void channelRead0(
                                ChannelHandlerContext channelHandlerContext,
                                    ByteBuf byteBuf) throws Exception {
                                if (connectFuture.isDone()) {
                                    // do something with the data
                                }
                            }
                        });
                ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));
                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();
                        }
                    }
                });
            }
        }
    
  5. 抽象类ChannelInboundHandlerAdapter定义了initChannel方法,可将多个ChannelHandler添加到一个ChannelPipeline中的简便方法,ChannelInitializer为其子类,只需重写该方法即可,一旦Channel被注册到了它的EventLoop之后,就会调用initChannel
    public class BootstrapWithInitializer {
        public void bootstrap() throws InterruptedException {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup())
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializerImpl());
            ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080));
            future.sync();
        }
    
        final class ChannelInitializerImpl extends ChannelInitializer {
            @Override
            protected void initChannel(Channel ch) throws Exception {
                ChannelPipeline pipeline = ch.pipeline();
                pipeline.addLast(new HttpClientCodec());
                pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));
    
            }
        }
    }
    
  6. ChannelOptionAttributeKey将在connect或者bind方法被调用时设置到已创建的Channel上,可在事件处理方法中使用
    public class BootstrapClientWithOptionsAndAttrs {
        public void bootstrap() {
            final AttributeKey id = AttributeKey.newInstance("ID");
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(new NioEventLoopGroup())
                .channel(NioSocketChannel.class)
                .handler(
                    new SimpleChannelInboundHandler() {
                        @Override
                        public void channelRegistered(ChannelHandlerContext ctx)
                            throws Exception {
                            Integer idValue = ctx.channel().attr(id).get();
                            // do something with the idValue
                        }
    
                        @Override
                        protected void channelRead0(
                            ChannelHandlerContext channelHandlerContext,
                            ByteBuf byteBuf) throws Exception {
                            System.out.println("Received data");
                        }
                    }
                );
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true)
                .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000);
            bootstrap.attr(id, 123456);
            ChannelFuture future = bootstrap.connect(
                new InetSocketAddress("www.manning.com", 80));
            future.syncUninterruptibly();
        }
    }
    
  7. Bootstrap也可用于无连接的协议,Netty 提供了各种DatagramChannel的实现,唯一区别就是不再调用connect,而只调用bind
    public class BootstrapDatagramChannel {
        public void bootstrap() {
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(new OioEventLoopGroup()).channel(
                OioDatagramChannel.class).handler(
                new SimpleChannelInboundHandler() {
                    @Override
                    public void channelRead0(ChannelHandlerContext ctx,
                        DatagramPacket msg) throws Exception {
                        // Do something with the packet
                    }
                }
            );
            ChannelFuture future = bootstrap.bind(new InetSocketAddress(0));
            future.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture channelFuture)
                   throws Exception {
                   if (channelFuture.isSuccess()) {
                       System.out.println("Channel bound");
                   } else {
                       System.err.println("Bind attempt failed");
                       channelFuture.cause().printStackTrace();
                   }
                }
            });
        }
    }
    
  8. EventLoopGroup.shutdownGracefully()会优雅的关闭Netty应用,关闭EventLoopGroup,处理任何挂起的事件和任务,随后释放所有活动的线程,返回一个Future,在关闭完成时接收通知
    public class GracefulShutdown {
        public static void main(String args[]) {
            GracefulShutdown client = new GracefulShutdown();
            client.bootstrap();
        }
        public void bootstrap() {
            EventLoopGroup group = new NioEventLoopGroup();
            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                 .channel(NioSocketChannel.class)
                 .handler(
                    new SimpleChannelInboundHandler() {
                        @Override
                        protected void channelRead0(
                                ChannelHandlerContext channelHandlerContext,
                                ByteBuf byteBuf) throws Exception {
                            System.out.println("Received data");
                        }
                    }
                 );
            bootstrap.connect(new InetSocketAddress("www.manning.com", 80)).syncUninterruptibly();      
            Future future = group.shutdownGracefully();
            // block until the group has shutdown
            future.syncUninterruptibly();
        }
    }
    

你可能感兴趣的:(第 8 章 引导)