小强前几天又催我了!拖不住了,源码开整!!
为了让大家由浅入深的理解源码,总体路线按照 调度器源码启动流程 -> 执行器源码启动流程 -> 任务调度核心源码,后面也会补充xxl-job的踩过的一些坑,以及定制化开发。
前置讲完了,撸起袖子开整!!走起,让我们先去看下任务调用端做了哪些事!!
文章目录
1.任务调用端Admin启动入口
启动的入口类为XxlJobAdminConfig类
@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}
// ---------------------- XxlJobScheduler ----------------------
private XxlJobScheduler xxlJobScheduler;
@Override
public void afterPropertiesSet() throws Exception {
adminConfig = this;
xxlJobScheduler = new XxlJobScheduler();
xxlJobScheduler.init();
}
@Override
public void destroy() throws Exception {
xxlJobScheduler.destroy();
}
}
先看下启动类XxlJobAdminConfig,这个启动类继承了InitializingBean,所以在项目启动的情况下会触发
afterPropertiesSet方法进行初始化,在初始化中构建XxlJobScheduler对象,并且调用init()初始化。
public void init() throws Exception {
// init i18n
initI18n();
// admin trigger pool start
// 初始化线程池,包含快慢两个线程池
JobTriggerPoolHelper.toStart();
// admin registry monitor run
// 负责执行器的注册和移除
JobRegistryHelper.getInstance().start();
// admin fail-monitor run
// 失败监控
JobFailMonitorHelper.getInstance().start();
// admin lose-monitor run ( depend on JobTriggerPoolHelper )
// 完成任务监控
JobCompleteHelper.getInstance().start();
// admin log report start
// 初始化日志记录器
JobLogReportHelper.getInstance().start();
// start-schedule ( depend on JobTriggerPoolHelper )
// 定时任务调度器
JobScheduleHelper.getInstance().start();
logger.info(">>>>>>>>> init xxl-job admin success.");
}
主要干的事:
- init i18n
- 初始化线程池,包含快慢两个线程池
- 负责执行器的注册和移除,维护注册表信息
- 任务执行监控
- 任务调度
2.启动流程
2.1 初始化触发线程池
public void start(){
//最大200个线程
fastTriggerPool = new ThreadPoolExecutor(
10,
XxlJobAdminConfig.getAdminConfig().getTriggerPoolFastMax(),
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(1000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-fastTriggerPool-" + r.hashCode());
}
});
//当任务再一分钟内超过10次时,会放入到慢触发器执行
slowTriggerPool = new ThreadPoolExecutor(
10,
XxlJobAdminConfig.getAdminConfig().getTriggerPoolSlowMax(),
60L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(2000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobTriggerPoolHelper-slowTriggerPool-" + r.hashCode());
}
});
}
关键:这里会初始化两个线程池,分别是快慢线程池。
快线程池用于处理时间短的任务,慢线程池用于处理时间长的任务。
当任务执行时,优先选择快触发器,当一分钟以内任务超过10次执行时间超过500ms时,则放到慢线程池触发器执行,这块可以把快慢任务进行隔离。
2.2 维护注册信息
主要有有两个线程池
public void start(){
// 负责注册或者移除执行器的线程池
registryOrRemoveThreadPool = new ThreadPoolExecutor(
2,
10,
30L,
TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(2000),
new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "xxl-job, admin JobRegistryMonitorHelper-registryOrRemoveThreadPool-" + r.hashCode());
}
},
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
r.run();
logger.warn(">>>>>>>>>>> xxl-job, registry or remove too fast, match threadpool rejected handler(run now).");
}
});
// 剔除超时执行器线程池
registryMonitorThread = new Thread(new Runnable() {
@Override
public void run() {
while (!toStop) {
try {
// auto registry group
List<XxlJobGroup> groupList = XxlJobAdminConfig.getAdminConfig().getXxlJobGroupDao().findByAddressType(0);
if (groupList!=null && !groupList.isEmpty()) {
// remove dead address (admin/executor)
// 获取90s内没有发送心跳的执行器
List<Integer> ids = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findDead(RegistryConfig.DEAD_TIMEOUT, new Date());
if (ids!=null && ids.size()>0) {
XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().removeDead(ids);
}
// fresh online address (admin/executor)
HashMap<String, List<String>> appAddressMap = new HashMap<String, List<String>>();
List<XxlJobRegistry> list = XxlJobAdminConfig.getAdminConfig().getXxlJobRegistryDao().findAll(RegistryConfig.DEAD_TIMEOUT, new Date());
if (list != null) {
for (XxlJobRegistry item: list) {