从零搭建xxl-job(七):xxl-job执行器服务端的简单搭建-2

上面我为大家引入了执行器端的服务器组件,并且讲解到了最核心的EmbedServer类,该类就是执行器端服务器的启动类,并且是以Netty构建的服务器。请看下面的代码块。

public class EmbedServer {

    private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);

    // 启动执行器的内嵌服务器,其中address参数就是执行器的IP地址,要封装到RegistryParam对象中发送给调度中心的
    // port为Netty构建的服务器要使用的端口号
    // appname为执行器配置文件中用户设定的执行器的唯一标识,时也要封装到RegistryParam对象中发送给调度中心的
    public void start(final String address, final int port, final String appName) {
        // 下面都是netty的知识,学习过netty的应该都清楚,就不再一一解释了。
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline()
                                    // 心跳检测
                                    .addLast(new IdleStateHandler(0, 0, 30 * 3, TimeUnit.SECONDS))
                                    // http的编解码器,该处理器既是出站处理器,也是入站处理器
                                    .addLast(new HttpServerCodec())
                                    // 这个处理器从名字上就能看出来,是聚合消息的,当喘气的http消息过大时,会被拆分开,这里添加这个处理器
                                    // 就是把拆分的消息再次聚合起来,形成一个整体再向后传递
                                    // 该处理器是个入站处理器
                                    .addLast(new HttpObjectAggregator(5 * 1024 * 1024))
                                    // 添加入站处理器,在该处理器中执行定时任务
                                    // 现在,EmbedHttpServerHandler这个消息处理器,就要实现最核心的功能了
                                    .addLast(new EmbedHttpServerHandler());
                        }
                    })
                    .childOption(ChannelOption.SO_KEEPALIVE,true);

            // 绑定端口号
            ChannelFuture future = bootstrap.bind(port).sync();
            // 注册执行器到调度中心
            startRegistry(appName,address);
            // 等待关闭
            future.channel().closeFuture().sync();
        }catch (InterruptedException e){
            logger.info(">>>>>>>>>>>>>>>>>>>>> yy-job remoting server stop");
        }finally {
            try {
                // 优雅释放资源
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();
            }catch (Exception e){
                logger.error(e.getMessage(), e);
            }
        }
    }
}

在上面的代码块中,我为大家展示了我自己构建的Netty的服务端,可以看到,这还是个http的服务端。因为在前 几章我就为大家讲解了,调度中心是通过http协议向执行器的服务器发送消息的,因此,执行器端内嵌的应该是一 个http服务器。既然是http服务器,就应该使用http的编解码器,在上面的代码块中,我为Netty服务端添加了四 个消息处理器,第一个处理器的作用是心跳检测,这也是Netty的知识点,就不再细说了。之后的 HttpServerCodec和HttpObjectAggregator服务器都是为http服务的,这里我也就不再详细讲解了。最后添加的那个EmbedHttpServerHandler处理器,才是我的服务端真正需要 的消息处理器,也就是我的业务处理器,当接收到调度中心发来的消息后,定时任务该如何执行,这个核心逻辑就 要在EmbedHttpServerHandler处理器中的channelRead方法中实现了。接下来,我就要为自己的程序具体编写该 处理器的逻辑了。

但是在我开始编写该处理器的逻辑之前,我想请大家稍微思考一下,刚才我跟大家说,在 EmbedHttpServerHandler处理器的channelRead方法中,被调度中心调度的定时任务就要开始执行了,这是不是 就意味着在该方法内定时任务会被执行。如果有很多定时任务,调度中心发送过来的消息都会传递到该处理器内, 被channelRead方法处理,这就意味着该执行器部署的很多定时任务都会在该方法内执行。如果大家对Netty足够 精通的话,肯定知道channelRead方法其实还是归Netty中的单线程执行器来调度的,而单线程执行器所做的工作 非常做,其中最重要的就是处理Selector上接收到的IO事件。本来单线程执行器的任务就比较多,处理完一次IO事 件后,就会紧接着处理下一个IO事件,因为调度中心会一直向执行器发送消息呀。但是现在单线程执行器在接收 到消息后,不仅要把消息传递到EmbedHttpServerHandler处理器的channelRead方法内,还要在该方法内执行对 应的定时任务,这么做对单线程执行器显然是一种拖累,就让单线程执行器迅速处理IO事件就行了。因此,这种 情况下,我们一般会创建一个业务线程池供EmbedHttpServerHandler处理器使用,定时任务也由业务线程池来执 行,以此达到和单线程执行器明确分工的效果。所以,EmbedServer类还应该小小地重构一下,添加一个线程 池,然后将这个线程池交给EmbedHttpServerHandler处理器使用。下面就是我重构好的EmbedServer类。

public class EmbedServer {

    private static final Logger logger = LoggerFactory.getLogger(EmbedServer.class);

    // 启动执行器的内嵌服务器,其中address参数就是执行器的IP地址,要封装到RegistryParam对象中发送给调度中心的
    // port为Netty构建的服务器要使用的端口号
    // appname为执行器配置文件中用户设定的执行器的唯一标识,时也要封装到RegistryParam对象中发送给调度中心的
    public void start(final String address, final int port, final String appName) {
        // 下面都是netty的知识,学习过netty的应该都清楚,就不再一一解释了。
        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        // 这就是我先创建好的业务线程池
        ThreadPoolExecutor bizThreadPool = new ThreadPoolExecutor(
                0,
                200,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(2000),
                new ThreadFactory() {
                    @Override
                    public Thread newThread(Runnable r) {
                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值