前言:最近学习到一个新的任务调度框架,觉得非常实用,能满足大部分的定时任务调度开发,故此记录
xxl-job 源码下载
github
gitee
官方文档
一、 xxl-job 相关
1、调度中心
调度中心我们可以理解为一个项目任务管理中心,我们通过注册的形式将一个个项目进行注入并且由调度中心进行统一管理。
2、执行器
假如我们基于微服务开发,每一个服务都有定时任务,每一个服务都需要注册到调度中心,那么这每一个服务都是一个执行器。
3、调度任务
每个服务中我们都有许多个定时任务,比如定时清理日志,定时登录,定时登出等等,这每一个定时任务就是一个调度任务。
二、xxl-job 调度中心
1、下载 xxl-job 源码
首先从 github 上将 xxl-job 的源码 zip 包下载进行接解压编译,解压编译后的目录如下
2、xxl-job 目录层级
xxl-job-admin 就是调度中心的源码
xxl-job-core 就是公共依赖
xxl-job-executor-samples:执行器 Sample 示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
xxl-job-executor-sample-springboot:Springboot 版本,通过 Springboot 管理执行器,推荐这种方式;
xxl-job-executor-sample-frameless:无框架版本;
3、配置调度中心数据库
下载后的源码目录中有一个数据库脚本
/xxl-job/doc/db/tables_xxl_job.sql
放到我们本地的 Mysql 中进行执行,会自动创建一个 xxl-job 的数据库,库中是调度中心所需要的相关表信息。
将 xxl-job-admin 中 application.properties 数据库连接改为我们自己的 Mysql 数据库连接地址
4、启动调度中心
调度中心访问地址:http://localhost:8080/xxl-job-admin
默认登录账号 “admin/123456”, 登录后运行界面如下图所示。
三、xxl-job 默认执行器和调度任务
1、默认执行器
下载的源码中自带两个执行器
xxl-job-executor-samples:执行器 Sample 示例(选择合适的版本执行器,可直接使用,也可以参考其并将现有项目改造成执行器)
xxl-job-executor-sample-springboot:Springboot 版本,通过 Springboot 管理执行器,推荐这种方式;
xxl-job-executor-sample-frameless:无框架版本;
我们可以直接启动 xxl-job-executor-sample-springboot 工程
启动之后,从执行器管理中就能看到默认执行器了
2、默认调度任务
查看 任务管理 也有一个默认的调度任务
默认执行器和默认调度任务具体功能大家可以自己研究一下
四、自定义执行器和调度任务
1、自定义执行器
新建一个 maven 工程 xxl-job-demo ,引入 xxl-job 核心依赖
<dependencies>
<!-- xxl-job-core -->
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.3.0</version>
</dependency>
</dependencies>
2、注册执行器
2.1、配置文件写入以下内容
server:
port: 7001
logging:
config: classpath:logback.xml
spring:
application:
name: xxl-job-demo
#集成xxl-job配置
xxl:
job:
### 是否开启job组件
enable: true
### 执行器通讯TOKEN [选填]:非空时启用;
accessToken:
admin:
### 调度中心部署跟地址 [选填]:如调度中心集群部署存在多个地址则用逗号分隔。执行器将会使用该地址进行"执行器心跳注册"和"任务结果回调";为空则关闭自动注册;
addresses: http://localhost:8080/xxl-job-admin
executor:
### 执行器AppName [选填]:执行器心跳注册分组依据;为空则关闭自动注册
appname: ${spring.application.name}
### 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
address:
### 执行器IP [选填]:默认为空表示自动获取IP,多网卡时可手动设置指定IP,该IP不会绑定Host仅作为通讯实用;地址信息用于 "执行器注册" 和 "调度中心请求并触发任务";
ip:
### 执行器端口号 [选填]:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
port: 27001
### 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logpath: ./xxl-job-logs/jobhandler
### 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
logretentiondays: 30
2.2、xxl-job 配置文件
/**
* @author wuxiongwei
* @date 2021/4/15 14:01
* @Description 获取配置文件 xxl-job 相关信息,注入 xxl-job 执行器
*/
@Configuration
public class XxlJobConfig {
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
@Value("${xxl.job.admin.addresses}")
private String adminAddresses;
@Value("${xxl.job.accessToken}")
private String accessToken;
@Value("${xxl.job.executor.appname}")
private String appname;
@Value("${xxl.job.executor.address}")
private String address;
@Value("${xxl.job.executor.ip}")
private String ip;
@Value("${xxl.job.executor.port}")
private int port;
@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.setAddress(address);
xxlJobSpringExecutor.setIp(ip);
xxlJobSpringExecutor.setPort(port);
xxlJobSpringExecutor.setAccessToken(accessToken);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
2.3、启动 xxl-job-demo
在调度中心中,将我们的工程新增
AppName 填我们配置文件定义的名称就可以
注册方式选择自动注册
新增之后,等待一小会儿,如果这个地址能自动获取到,就代表我们已经注册成功了
3、新增调度任务
调度任务新增有两种方式
一种是方法级别,每个方法上增加 @XxlJob 注解
一种是类级别,通过 XxlJobSpringExecutor.registJobHandler(value, job)
3.1、方法级别
/**
* @author wuxiongwei
* @date 2021/4/15 14:01
* @Description xxl-job bean 方法形式注入定时任务
*/
@Component
public class SampleBeanXxlJob {
private static Logger logger = LoggerFactory.getLogger(SampleBeanXxlJob.class);
/**
* 1、简单任务示例(Bean模式)
*/
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
logger.info("XXL-JOB, Hello World.");
}
}
3.2、类级别
1、开发一个继承自"com.xxl.job.core.handler.IJobHandler"的JobHandler类,实现其中任务方法。
2、手动通过如下方式注入到执行器容器。
XxlJobExecutor.registJobHandler("demoJobHandler", new DemoJobHandler());
3.3、自定义类级别
由于本人偏向于使用类级别,所以针对 类级别 做了些许优化,如下
新建一个注解
/**
* @author wuxiongwei
* @date 2021/4/15 14:01
* @Description 自定义类形式注入 xxl-job 注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XxlJobHandler {
String value();
}
自定义类级别使用方式
/**
* XxlJob开发示例(类模式)
*/
@Component
@XxlJobHandler("sampleClassXxlJob")
public class SampleClassXxlJob extends IJobHandler {
private static Logger logger = LoggerFactory.getLogger(SampleClassXxlJob.class);
@Override
public void execute() throws Exception {
logger.info("类定时任务执行。。。。");
}
}
扫描所有的自定义类级别,统一进行注入
/**
* @author wuxiongwei
* @date 2021/4/15 14:01
* @Description 扫描所有类形式 job ,统一注册到 xxl-job
* 必须开启配置,才会进行装配
*/
@ConditionalOnProperty(prefix = "xxl.job", name = "enable", havingValue = "true")
@Configuration
public class XxlRegistJobHandlerConfig {
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
//注入所有实现了 IJobHandler 的类
@Autowired(required = false)
List<IJobHandler> jobHandlerList;
@PostConstruct
private void init() {
if (CollectionUtils.isEmpty(jobHandlerList)) {
logger.warn("在Spring容器中没有检测到Job对象,请确保Job对象实现IJobHandler接口,并且应用了@XxlJobHandler注解");
return;
}
scanRegistJobHandler();
}
private void scanRegistJobHandler() {
//防止jobHandler名称重复
Set<String> jobNames = new HashSet<>();
jobHandlerList.stream().filter(job -> {
boolean implementsSimpleJob = IJobHandler.class.isAssignableFrom(job.getClass());
boolean hasJobDefine = job.getClass().getAnnotation(XxlJobHandler.class) != null;
return implementsSimpleJob && hasJobDefine;
}).forEach(job -> {
XxlJobHandler def = job.getClass().getAnnotation(XxlJobHandler.class);
final String value = def.value();
if (jobNames.contains(value)) {
throw new RuntimeException("定时任务名重复注册,任务job名:"+value);
}
jobNames.add(value);
XxlJobSpringExecutor.registJobHandler(value, job);
});
}
}
3.4、任务管理中进行配置
每一个调度任务,不管是方法级别还是类级别,新增之后都需要到调度中心的任务管理进行新增
执行器:当前 job 所在的执行器,也就是我们注册的工程名称
JobHandler:就是我们在方法级别或者类级别中定义的 job 名称
五、调度任务执行
每一个调度任务都可以进行相关操作,启动、停止、手动执行等等
六、调度任务执行日志
xxl-job 还有很多功能,我这里就不一一介绍了,感兴趣的可以自己看看官方文档,中文文档,上手还是很快的。