xxl 源碼分析

目錄:

調度中心端如何進行任務管理及調度

分佈式調度平臺XXL-JOB源碼分析-執行器端

----------------------------------------------------------

調度中心端如何進行任務管理及調度

架構圖:

 

xxl 上圖是我們要進行源碼分析的2.1版本的整體架構圖。其分爲兩大塊,調度中心和執行器,本文先分析調度中心,也就是xxl-job-admin這個包的代碼。

在application.properties配置正確的數據庫連接信息後,直接啓動XxlJobAdminApplication即可。

配置類XxlJobAdminConfig,裏面維護了一些調度中心端的配置數據。

XxlJobScheduler這個組件實現了InitializingBean接口,所以spring容器在初始化的時候會調用afterPropertiesSet方法,此方法如下:

第一步國際化相關。

第二步監控相關。

第三步失敗重試相關。

第四步啓動admin端服務,接收註冊請求等。

第五步JobScheduleHelper調度器,死循環,在xxl_job_info表裏取將要執行的任務,更新下次執行時間的,調用JobTriggerPoolHelper類,來給執行器發送調度任務的.

 

JobScheduleHelper

這個類就是死循環從xxl_job_info表中取出未來5秒內要執行的任務,進行調度分發。

啓動了兩個守護線程,先來看scheduleThread。

死循環內的代碼如上圖,首先利用for update語句進行獲取任務的資格鎖定,再去獲取未來5秒內即將要執行的任務。

ringData是以0到59的整數爲key,以jobId集合爲value的Map集合。這個集合數據的處理邏輯,就在我們第二個守護線程ringThread中。

while (!ringThreadToStop) {
 2     try {
 3         // second data
 4         List<Integer> ringItemData = new ArrayList<>();
 5         int nowSecond = Calendar.getInstance().get(Calendar.SECOND);   // 避免處理耗時太長,跨過刻度,向前校驗一個刻度;
 6         for (int i = 0; i < 2; i++) {
 7             List<Integer> tmpData = ringData.remove( (nowSecond+60-i)%60 );
 8             if (tmpData != null) {
 9                 ringItemData.addAll(tmpData);
10             }
11         }
12         // ring trigger
13         logger.debug(">>>>>>>>>>> xxl-job, time-ring beat : " + nowSecond + " = " + Arrays.asList(ringItemData) );
14         if (ringItemData!=null && ringItemData.size()>0) {
15             // do trigger
16             for (int jobId: ringItemData) {
17                 // do trigger
18                 JobTriggerPoolHelper.trigger(jobId, TriggerTypeEnum.CRON, -1, null, null);
19             }
20             // clear
21             ringItemData.clear();
22         }
23     } catch (Exception e) {
24         if (!ringThreadToStop) {
25             logger.error(">>>>>>>>>>> xxl-job, JobScheduleHelper#ringThread error:{}", e);
26         }
27     }
28     // next second, align second
29     try {
30         TimeUnit.MILLISECONDS.sleep(1000 - System.currentTimeMillis()%1000);
31     } catch (InterruptedException e) {
32         if (!ringThreadToStop) {
33             logger.error(e.getMessage(), e);
34         }
35     }
36 }

複製代碼

 

 

minTim屬性,作用待明確

jobTimeoutCountMap屬性,計數,key爲jobId,value使用AtomicInteger計數。

helper靜態變量指向自己本身,提供外部靜態方法調用。

重要方法,向兩種線程池其中之一提交調度任務,進行調度,引出XxlJobTrigger這個類,一路跟進去.

 

分佈式調度平臺XXL-JOB源碼分析-執行器端

XxlJobExecutorApplication爲我們執行器的啓動項,其中有個XxlJobConfig的配置項,發現其中有個屬性爲adminAddresses,這個就是我們調度中心的地址。

XxlJobSpringExecutor

 

聲明瞭init方法爲start,點進來,

它又實現了ApplicationContextAware接口,用來保存spring的上下文信息。

它還有個父類XxlJobExecutor,暫時未找到其他子類。

程序開始執行start方法:

第一步,調用了本類的私有方法,這個方法就是把JobHandler的實現類取出來,再調用registJobHandler(name, handler)進行註冊。

1.日誌處理器初始化

2.向adminBizList字段中放入XxlRpcReferenceBean返回的代理類,作用之後會單獨開一篇註冊心跳的文章說明。

3.任務日誌清除

4.任務結果回調處理線程

5.啓動另一個執行器的執行線程XxlRpcProviderFactory這個類是XXl其他的開源項目,自研RPC

XxlRpcProviderFactory

看名字就知道這個類是可以返回Rpc調用服務提供端的工廠類,接上文,看他的initRpcProvider方法。

此時的ServiceRegistry爲ExecutorServiceRegistry,調用其start,以30秒的間隔和調度中心進行心跳通知,然後調用server的start方法,此時server爲NettyHttpServer.

 

 

 從serviceData中拿到我們之前調用addService方法添加的服務實現類,這裏是ExecutorBizImpl,這裏反射調用的方法是run。 

 

如果沒有正在執行此任務的線程,那就調用XxlJobExecutor.registJobThread()啓動一個線程,最後將任務數據推送給這個可能是從jobThreadRepository獲取到的也可能是新創建的線程,如下圖。

 

 

 至此,執行器完成了啓動,暴露ExecutorBiz服務,接收任務調度數據TriggerParam,並在JobThread線程中完成任務配置的業務handler的執行。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章