阅读XXL-Job源码-客户端

59 阅读2分钟

从XxlJobSpringExecutor开始

图片.png

两个步骤:

1、initJobHandlerMethodRepository(applicationContext); //注册定义的JobHandler 2、super.start(); //启动

1. initJobHandlerMethodRepository:

将应用中自定义的JobHandler 扫描出来 @XxlJob,并注册到 ConcurrentMap<String, IJobHandler> jobHandlerRepository中。

源码如下:

            // generate and regist method job handler
            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();
                // regist
                registJobHandler(xxlJob, bean, executeMethod);
            }

进入registJobHandler(xxlJob, bean, executeMethod)方法

// registry jobhandler
        registJobHandler(name, new MethodJobHandler(bean, executeMethod, initMethod, destroyMethod));
// ---------------------- job handler repository ----------------------
    private static ConcurrentMap<String, IJobHandler> jobHandlerRepository = new ConcurrentHashMap<String, IJobHandler>();
    
jobHandlerRepository.put(name, jobHandler);
2. start():

先看源码

public void start() throws Exception {

        // init logpath
        XxlJobFileAppender.initLogPath(logPath);

        // init invoker, admin-client
        initAdminBizList(adminAddresses, accessToken, timeout);


        // init JobLogFileCleanThread
        JobLogFileCleanThread.getInstance().start(logRetentionDays);

        // init TriggerCallbackThread
        TriggerCallbackThread.getInstance().start();

        // init executor-server
        initEmbedServer(address, ip, port, appname, accessToken);
    }

TriggerCallbackThread.getInstance().start():

会创建两个线程triggerCallbackThread、triggerRetryCallbackThread 并启动。

initEmbedServer(address, ip, port, appname, accessToken):

创建一个http server,用于接收服务端的操作指令,如 "/beat" "/idleBeat" "/run" "/kill" 等。实际上会调用ExecutorBizImpl对象的方法

同时会将自己注册到服务端中 startRegistry(appname, address);

    ExecutorRegistryThread.getInstance().start(appname, address);

继续点进去

image.png 我们还能看到每次注册后,会睡眠默认30s

    TimeUnit.SECONDS.sleep(RegistryConfig.BEAT_TIMEOUT);

ExecutorBizImpl 这个对象就是执行具体的操作指令

执行job的代码截图:ExecutorBizImpl.run()方法

image.png

先loadJobThread(第一次为null)—— 从jobThread中取出jobHandle —— 如果取不到jobHandle, 则从map中取出jobHandle(因为jobHandle都注册到ConcurrentMap<String, IJobHandler> jobHandlerRepository中了)

拿到jobHandler之后,会创建JobThread对象 jobThread = XxlJobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);

然后 jobThread.pushTriggerQueue(triggerParam) 将请求参数放入triggerQueue中,jobThread再去执行jobHandle

image.png

创建XxlJobContext对象后,调用 handler.execute();执行job方法。 执行完成后会处理返回值,比如异常时的信息。

执行完成后会回调XXL Job服务器:adminBiz.callback(callbackParamList)

至此,一个执行过程就完成了。

总结一下:

  1. 客户端项目启动后,会扫描自定义的jobHandle(即自己写的定时任务的方法),并注册到jobHandlerRepository的Map中。
  2. 会初始化一些线程:triggerCallbackThread(用于回调XxlJob服务器)、triggerRetryCallbackThread(应该是重试逻辑吧??);
  3. 初始化一个http server,用于接收XxlJob服务器的http请求命令,如/run。
  4. 将客户端自己注册到XxlJob服务器,每30s注册一次。
  5. 当XxlJob发起/run时,客户端先从内存中获取jobHandle,(第一次会创建JobThread),再 triggerQueue.add(triggerParam);
  6. JobThread去消费triggerQueue,执行 handler.execute(),再处理执行结果是成功还是失败。再将结果通过回调接口返回给XXL Job服务器。