執行器的分類
xxl-job一共定義了5種類型的執行器,這裏放個截圖
這裏我們挑選springboot項目來進行分析。
源碼分析
- 既然是boot項目,那麼首先肯定是找執行類:
XxlJobExecutorApplication
,這是個簡單的啓動類。
public static void main(String[] args) {
SpringApplication.run(XxlJobExecutorApplication.class, args);
}
- 之後會進入配置類:
XxlJobConfig
,這裏會讀取resources/application.properties
的配置信息,然後執行xxlJobExecutor()
方法,貼下代碼。
@Bean(initMethod = "start", destroyMethod = "destroy")
public XxlJobSpringExecutor xxlJobExecutor() {
logger.info(">>>>>>>>>>> xxl-job config init.");
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
xxlJobSpringExecutor.setAppName(appName);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
- 這裏可以看到接下來就會調用
XxlJobSpringExecutor
的start()
方法,OK,讓我們在來看看他做了什麼。
@Override
public void start() throws Exception {
// 註冊所有的jobHandler
initJobHandlerRepository(applicationContext);
// 不是很重要,就是註冊個工程
GlueFactory.refreshInstance(1);
// 調用父類的start方法
super.start();
}
- 父類也就是
XxlJobExecutor
的start()
方法執行,我們在來看看。
public void start() throws Exception {
// 初始化日誌路徑
XxlJobFileAppender.initLogPath(logPath);
// 初始化調度中心的本地列表
initAdminBizList(adminAddresses, accessToken);
// 日誌清除線程
JobLogFileCleanThread.getInstance().start(logRetentionDays);
// 回調線程開啓
TriggerCallbackThread.getInstance().start();
port = port>0?port: NetUtil.findAvailablePort(9999);
ip = (ip!=null&&ip.trim().length()>0)?ip: IpUtil.getIp();
// 初始化服務器
initRpcProvider(ip, port, appName, accessToken);
}
- 這裏需要關注的是
initAdminBizList()
和initRpcProvider()
,那麼同樣看代碼。
private void initAdminBizList(String adminAddresses, String accessToken) throws Exception {
if (adminAddresses!=null && adminAddresses.trim().length()>0) {
for (String address: adminAddresses.trim().split(",")) {
if (address!=null && address.trim().length()>0) {
String addressUrl = address.concat(AdminBiz.MAPPING);
AdminBiz adminBiz = (AdminBiz) new XxlRpcReferenceBean(
NetEnum.JETTY,
Serializer.SerializeEnum.HESSIAN.getSerializer(),
CallType.SYNC,
LoadBalance.ROUND,
AdminBiz.class,
null,
10000,
addressUrl,
accessToken,
null,
null
).getObject();
if (adminBizList == null) {
adminBizList = new ArrayList<AdminBiz>();
}
adminBizList.add(adminBiz);
}
}
}
}
這裏主要意思就是得到AdminBiz
代理並放入到adminBizList
集合中,獲取代理的方法是getObject()
,然後接着看,接下來就是完成向任務調度中心發送請求進行服務註冊操作,我們主要看如何發起請求的代碼。
client.asyncSend(finalAddress, xxlRpcRequest);
這裏會有三種實現,xxl-job
默認採用JettyClient
,繼續追蹤會發現其實就是封裝了一個Request請求,然後向註冊中心發送。這樣註冊流程就完成了。
- 接下來該看看
initRpcProvider()
方法,那這個方法做了什麼呢?想必看名字也大概知道了,沒錯,就是啓動一個web服務,供之後調度中心的分發任務,看代碼。
private void initRpcProvider(String ip, int port, String appName, String accessToken) throws Exception {
// 初始化服務註冊工廠
String address = IpUtil.getIpPort(ip, port);
Map<String, String> serviceRegistryParam = new HashMap<String, String>();
serviceRegistryParam.put("appName", appName);
serviceRegistryParam.put("address", address);
xxlRpcProviderFactory = new XxlRpcProviderFactory();
xxlRpcProviderFactory.initConfig(NetEnum.JETTY, Serializer.SerializeEnum.HESSIAN.getSerializer(), ip, port, accessToken, ExecutorServiceRegistry.class, serviceRegistryParam);
// 添加服務
xxlRpcProviderFactory.addService(ExecutorBiz.class.getName(), null, new ExecutorBizImpl());
// 啓動一個web服務
xxlRpcProviderFactory.start();
}
- 在進入
start()
方法。
public void start() throws Exception {
// start server
serviceAddress = IpUtil.getIpPort(this.ip, port);
server = netType.serverClass.newInstance();
server.setStartedCallback(new BaseCallback() { // serviceRegistry started
@Override
public void run() throws Exception {
// start registry
if (serviceRegistryClass != null) {
serviceRegistry = serviceRegistryClass.newInstance();
serviceRegistry.start(serviceRegistryParam);
if (serviceData.size() > 0) {
serviceRegistry.registry(serviceData.keySet(), serviceAddress);
}
}
}
});
server.setStopedCallback(new BaseCallback() { // serviceRegistry stoped
@Override
public void run() {
// stop registry
if (serviceRegistry != null) {
if (serviceData.size() > 0) {
serviceRegistry.remove(serviceData.keySet(), serviceAddress);
}
serviceRegistry.stop();
serviceRegistry = null;
}
}
});
//前面就是一些地址,回調的設置,這裏就是啓動了一個jetty服務
server.start(this);
}
- 至此,執行器的任務基本完成,來總結下,執行器啓動後,首先會向註冊中心註冊自身,然後自己會啓動一個jetty服務供之後的註冊中心來分發任務。