xxl-job是一个任务调度平台,能够设置调度的策略。相对于之前spring 提供的@Sheduel,xxl-job能够支持分布式调度,提供了很多方便、易用的功能,下面会详细介绍它的使用和原理
xxl-job整体框架分为两个部分调度中心和执行器,先来了解它的使用部分
如何使用
从码云中下载xxl-job项目 https://gitee.com/xuxueli0323/xxl-job
调度中心启动
admin模块为调度中心,从doc文件夹下获取数据库的建表sql,在数据库中执行后将数据库的连接配置在application.properties中,启动项目
浏览器中访问地址:http://localhost:8080/xxl-job-admin
输入默认用户名 admin、密码 123456 登录
执行器的启动
执行器一般是集成在项目中,在项目中引入依赖
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.4.0</version>
</dependency>
设置配置信息
logging:
#配置日志格式信息
config: classpath:logback.xml
xxl:
job:
executor:
#执行器应用名称、ip、port
appname: xxl-job-executor-helloword
ip: localhost
port: 8071
# 存放日志的配置文件
logpath: /data/applogs/xxl-job/jobhandler
# 日志文件存储时间,超过设置时间会清除
logretentiondays: 3
#设置 通信accessToken
accessToken: default_token
admin:
#设置 调度中心的地址
addresses: http://127.0.0.1:8080/xxl-job-admin
解析配置信息
@Configuration
//指定任务Handler所在包路径
@ComponentScan(basePackages = "com.person.xxlJob.executor")
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.executor.appname}")
private String appName;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.logpath}")
private String logPath;
@Value("${xxl.job.executor.logretentiondays}")
private int logRetentionDays;
@Bean
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;
}
}
任务设置
@Component
public class DemoJobHandler{
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
XxlJobHelper.log("XXL-JOB, Hello World.");
for (int i = 0; i < 5; i++) {
XxlJobHelper.log("beat at:" + i);
TimeUnit.SECONDS.sleep(2);
}
// default success
}
}
启动项目后,查看调度中心注册的执行器
需要手动添加执行器的分组信息
在执行器发送心跳信息后,就可查看注册的执行器信息
点击查看,可以看到注册的执行器列表
新增任务执行
启动任务后可以查看调度日志信息
原理分析
我们先看下官方的架构图
执行器注册过程
执行器启动时首先会注册地址信息到调度中心,调度中心执行任务时才能有执行器去执行
从xxl-job配置类入手,从前面的配置中可以看到定义了类XxlJobSpringExecutor,查看这个类实现了接口SmartInitializingSingleton,项目启动时在所有类实例化后会调用接口的实现方法afterSingletonsInstantiated
public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
private static final Logger logger = LoggerFactory.getLogger(XxlJobSpringExecutor.class);
private static ApplicationContext applicationContext;
public XxlJobSpringExecutor() {
}
public void afterSingletonsInstantiated() {
this.initJobHandlerMethodRepository(applicationContext);
GlueFactory.refreshInstance(1);
try {
//查看父类的方法
super.start();
} catch (Exception var2) {
throw new RuntimeException(var2);
}
}
...
}
//父类XxlJobExecutor中的start()方法,可以看见服务ip、port的信息
public void start() throws Exception {
XxlJobFileAppender.initLogPath(this.logPath);
this.initAdminBizList(this.adminAddresses, this.accessToken);
JobLogFileCleanThread.getInstance().start((long)this.logRetentionDays);
TriggerCallbackThread.getInstance().start();
//这个方法实现 服务的注册
this.initEmbedServer(this.address, this.ip, this.port, this.appname, this.accessToken);
}
//最后在类AdminBizClient中查看具体的调用信息
public ReturnT<String> registry(RegistryParam registryParam) {
return XxlJobRemotingUtil.postBody(this.addressUrl + "api/registry", this.accessToken, this.timeout, registryParam, String.class);
}
任务调度执行的过程
查看Admin中的配置类XxlJobAdminConfig ,实现了接口InitializingBean,在类初始化时会调用接口的实现方法
@Component
public class XxlJobAdminConfig implements InitializingBean, DisposableBean {
private static XxlJobAdminConfig adminConfig = null;
public static XxlJobAdminConfig getAdminConfig() {
return adminConfig;
}
private XxlJobScheduler xxlJobScheduler;
@Override
public void afterPropertiesSet() throws Exception {
adminConfig = this;
xxlJobScheduler = new XxlJobScheduler();
//调用init方法时,会执行设置的任务
xxlJobScheduler.init();
}
...//其他代码没有复制,省略
}
public class XxlJobScheduler {
private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);
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.");
}
...
}
调度线程会将任务放到时间轮中,根据设置的规则定时调度任务,调度任务选择执行器时根据路由策略选择执行器,执行器执行完成任务后,将任务结果发送到调度中心