zoukankan      html  css  js  c++  java
  • Netty 启动引导类组件作用

    一个 Netty 应用通常由一个 Bootstrap 开始,主要作用是配置整个 Netty 程序,串联各个组件,而客户端和服务端这两种应用程序间通用的引导步骤有AbstractBootstrap处理,Netty 中 Bootstrap 类是客户端程序的启动引导类,ServerBootstrap 是服务端启动引导类;

    引导类的层次结构

    为何引导类要实现Cloneable接口?

    有时可能会需要创建多个具有类似配置或者完全相同配置的Channel(如链式调用那里添加配置);为了支持这种模式而又不需要为每个Channel都创建并配置一个新的引导类实例,AbstractBootstrap被标记为Cloneable的引导类实例;

    注意,这种方式只会创建引导类实例的EventLoopGroup的一个浅拷贝,所以被浅拷贝的EventLoopGroup将在所有克隆的Channel实例之间共享;这是可以接受的,因为通常这些克隆的Channel的生命周期都很短暂;如创建一个Channel以进行一次HTTP请求;

    对于AbstractBootstrap的子类型 B 是其父类型的一个类型参数,因此可以返回到运行时实例的引用以支持方法的链式调用(也就是所谓的流式语法

    引导客户端

    Bootstrap 类负责为客户端和使用无连接协议的应用程序创建 Channel;

    使用如下:

    public class NettyClient {
        public static void main(String[] args) {
            final int port = 19000;
            final String local = "127.0.0.1";
            EventLoopGroup group = new NioEventLoopGroup();
    
            try {
                // 创建一个BootStrap类的实例以创建和连接新的Channel
                Bootstrap bootstrap = new Bootstrap();
    
                // 链式写法
                // 设置EventLoopGroup,提供用于处理Channel事件的EventLoop
                bootstrap.group(group)
                        // 指定要使用的Channel实现
                        .channel(NioSocketChannel.class)
                        // 设置用于用于处理Channel事件的Handler
                        .handler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline().addLast(new NettyClientHandler());
                            }
                        });
    
                // 连接服务端
                ChannelFuture channelFuture = bootstrap.connect(local, port).sync();
                channelFuture.channel().closeFuture().sync();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                group.shutdownGracefully();
            }
        }
    }
    

    除了 connect()方法以外, BootStrap的其他方法将通过每次方法调用所返回Bootstrap 实例的引用;

    在引导的过程中,在调用 bind()或者 connect()方法之前,必须调用以下方法来设置所需的组件(如果不这样做, 则将会导致 IllegalStateException):

    • group();
    • channel()或者 channelFactory();
    • handler();需要通过该方法配置 ChannelPipeline;

    引导服务器

    ServerBootstrap 是服务端启动引导类;

    ServerBootstrap 在 bind()方法被调用时创建了一个 ServerChannel,并且该 ServerChannel 管理了多个子 Channel;

    ServerChannel的实现负责创建子 Channel,这些子Channel 代表了已被接受的连接(已连接的客户端)

    负责引导 ServerChannel 的 ServerBootstrap 提供了的方法,以简化将设置应用到已被接受的子Channel的ChannelConfig 的任务;

    使用如下:

    public class NettyServer {
    
        private final static Logger logger = LoggerFactory.getLogger(NettyServer.class);
    
        public static void main(String[] args) {
            // 创建两个线程组bossGroup和workerGroup,含有子线程NioEventLoop的个数默认为cpu核数的两倍
            // bossGroup只处理连接请求,业务处理交由wokerGroup
            EventLoopGroup bossGroup = new NioEventLoopGroup(1);
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            final int port = 19000;
    
            try {
                // 创建服务的启动对象
                ServerBootstrap bootstrap = new ServerBootstrap();
    
                // 设置两个线程组
                bootstrap.group(bossGroup, workerGroup)
                        // 指定使用NioServerSocketChannel作为服务器的通道实现
                        .channel(NioServerSocketChannel.class)
                        // 初始化服务器连接队列大小,服务端处理客户端连接请求是顺序处理的,所以同一时间只能处理一个客户端连接
                        // 多个客户端同时来的时候,服务端将不能处理的客户端连接请求放在队列中等待处理
                        .option(ChannelOption.SO_BACKLOG, 1024)
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            //创建通道初始化对象,设置初始化参数
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                //对workerGroup的SocketChannel设置处理器codec
                                ch.pipeline().addLast(new NettyServerHandler());
                            }
                        });
    
                logger.info("netty server start...");
    
                // 通过配置好ServerBootStrap的实例绑定该Channel
                // 启动服务器(并绑定端口),bind是异步操作,sync方法是等待异步操作执行完毕,这里会阻塞住
                ChannelFuture channelFuture = bootstrap.bind(port).sync();
    
                // 添加监听器
                channelFuture.addListener(new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                        if (future.isSuccess()) {
                            logger.info("监听端口" + port + "成功");
                        } else {
                            logger.info("监听失败...");
                        }
                    }
                });
    
                channelFuture.channel().closeFuture().sync();
            } catch (Exception e) {
                logger.error("异常..", e);
            } finally {
                bossGroup.shutdownGracefully();
                workerGroup.shutdownGracefully();
            }
        }
    }
    

     

    如果服务器正在处理一个客户端的请求,这个请求需要它充当第三方系统的客户端;
    当一个应用程序(如一个代理服务器)必须要和组织现有的系统(如 Web 服务或者数据库)集成时,就可能发生这种情况; 在这种情况下,将需要从已经被接受的子 Channel 中引导一个客户端 Channel;

    如果创建新的BootStrap实例,并且每个新创建的客户端 Channel 定义另一个 EventLoop,这会产生额外的线程,以及在已被接受的子 Channel 和客户端 Channel 之间交换数据时不可避免的上下文切换;


    通过将已被接受的子 Channel(已连接的客户端) EventLoop 传递给 Bootstrap的 group()方法来共享该 EventLoop;因为分配给 EventLoop 的所有 Channel 都使用同一个线程,所以这避免了额外的线程创建和Channel之间数据交换时的上下文切换;如下图;

      

    写法如下:

     
  • 相关阅读:
    通过python来获取网页状态
    php多域名跳转nginx
    mybatis-plus主键策略
    mybatis-plus ActiveRecord模式
    mybatis-plus-Cud操作
    mybatis-plus高级操作
    mybatis-plus入门
    ☕【Java技术指南】「序列化系列」深入挖掘FST快速序列化压缩内存的利器的特性和原理
    虚拟机研究系列-「GC本质底层机制」SafePoint的深入分析和底层原理探究指南
    👊 Spring技术原理系列(7)带你看看那些可能你还不知道的Spring特性技巧哦!
  • 原文地址:https://www.cnblogs.com/coder-zyc/p/14418925.html
Copyright © 2011-2022 走看看