前言:在之前的文章中,我写过springboot集成quartz框架在实际项目中的应用。但是由于quartz框架的一些缺点,而xxl-job能完美克服这些缺点,也是当前市面上使用相对较多的定时任务框架。xxl-job提供了调度中心控制台页面,对所有的定时任务进行统一配置管理。在我之前的文章中写了一篇搭建调度中心的详细过程:https://blog.csdn.net/qq798867485/article/details/131415408。有不会搭建的同学可以先搭建,因为要使用xxljob必须要有调度中心提供服务,下面就详细介绍springboot整合xxl-job项目使用。
一、整合xxl-job
引入xxljob的依赖
dependency>
groupId>com.xuxueligroupId>
artifactId>xxl-job-coreartifactId>
version>2.3.1version>
dependency>
在yml加上xxljob的配置
xxl:
job:
admin:
# 调度中心服务部署的地址
addresses: http://localhost:8022/xxl-job-admin
# 执行器通讯TOKEN,要和调度中心服务部署配置的accessToken一致,要不然无法连接注册
accessToken: default_token777
executor:
# 执行器AppName
appname: job-demo
# 执行器注册 [选填]:优先使用该配置作为注册地址,为空时使用内嵌服务 ”IP:PORT“ 作为注册地址。从而更灵活的支持容器类型执行器动态IP和动态映射端口问题。
address:
ip:
#执行器端口号:小于等于0则自动获取;默认端口为9999,单机部署多个执行器时,注意要配置不同执行器端口;
port: 8889
# 执行器运行日志文件存储磁盘路径 [选填] :需要对该路径拥有读写权限;为空则使用默认路径;
logpath:
# 执行器日志文件保存天数 [选填] : 过期日志自动清理, 限制值大于等于3时生效; 否则, 如-1, 关闭自动清理功能;
logretentiondays: 30
加上配置类,启动springboot项目时连接调度中心服务
XxlJobConfig.java
package com.example.xxjob.config;
import com.example.xxjob.job.DemoHandler;
import com.xxl.job.core.executor.XxlJobExecutor;
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Arrays;
@Configuration
@Slf4j
public class XxlJobConfig {
@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() {
log.info(">>>>>>>>>>> start 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);
log.info(">>>>>>>>>>> end xxl-job config init. >>>>>>>>");
return xxlJobSpringExecutor;
}
}
启动springboot应用就可以看到能够连接xxl-job调度中心
二、编写定时任务(无参)
创建一个service层的类,来模拟实际业务中service层的类的调用
package com.example.xxjob.service;
public interface UserService {
void demoJob();
}
package com.example.xxjob.service.impl;
import com.example.xxjob.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service("userService")
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public void demoJob() {
log.info(">>>>>>>>>> 开始处理实际业务逻辑 >>>>>>>>>>>>>>>");
log.info(">>>>>>>>>> 完成处理实际业务逻辑 >>>>>>>>>>>>>>>");
}
}
2.1 BEAN模式(类形式)(不推荐)
Bean模式任务,支持基于类的开发方式,每个任务对应一个Java类。
- 优点:不限制项目环境,兼容性好。即使是无框架项目,如main方法直接启动的项目也可以提供支持,
- 缺点:
- 每个任务需要占用一个Java类,造成类的浪费;
- 不支持自动扫描任务并注入到执行器容器,需要手动注入。
而且还有一个很不好的缺点,就是没法使用@Autowired 或者 @Resource 把bean注入,不然会报空指针异常
2.1.1 新建一个定时任务
package com.example.xxjob.job;
import com.example.xxjob.service.UserService;
import com.example.xxjob.service.impl.UserServiceImpl;
import com.xxl.job.core.handler.IJobHandler;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class DemoHandler extends IJobHandler {
private final UserService userService = new UserServiceImpl();
@Override
public void execute() throws Exception {
log.info(">>>>>>>>>> BEAN模式(类形式) 开始 >>>>>>>>>>>>>>>");
userService.demoJob();
log.info(">>>>>>>>>> BEAN模式(类形式) 成功 >>>>>>>>>>>>>>>");
}
}
2.1.2 手动注入到执行器容器
XxlJobExecutor.registJobHandler("demoHandler", new DemoHandler());
2.1.3 到调度中心执行器管理–新增执行器(也就是你的应用程序)
AppName: 和项目中yml文件配置的appname 的值一致
名称: 测试应用
注册方式:
-- 自动注册:就无需配置ip和端口
-- 手动录入:需要把你项目中的ip(域名)和端口录入
2.1.3 到调度中心任务管理–新增定时任务(也就是项目中的定时任务)
执行器:定时任务所在的项目,跟上一步执行器的名称一致
调度类型:Core
core表达式:根据需求中定时任务实际情况定
运行模式: BEAN
JobHandler:demoHandler,跟注入到执行器容器名称一致
剩下的一些选项可以默认,也可以根据你实际情况定。
2.1.4 执行定时任务和查看日志
2.2 BEAN模式(方法形式)(推荐)
2.2.1 新建一个定时任务
package com.example.xxjob.job;
import com.example.xxjob.service.UserService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class DemoJob {
@Autowired
private UserService userService;
@XxlJob("demoJobHandler")
public void demoJobHandler() throws Exception {
log.info(">>>>>>>>>> BEAN模式(类形式) 开始 >>>>>>>>>>>>>>>");
userService.demoJob();
log.info(">>>>>>>>>> BEAN模式(类形式) 成功 >>>>>>>>>>>>>>>");
}
}
2.2.2 后续步骤和 “2.1 BEAN模式(类形式)”一致,新增定时任务,然后执行即可。
三、定时任务迁移(选)
这个需求的是,公司原先项目中的使用的定时任务框架是quartz,现在要全部改为整合xxl-job来管理所有的定时任务。
首先还是要部署调度中心,配置和新建执行器和之前的步骤是一样的。这里有所不同的是定义一个定时任务,通过传参就可以
知道执行定时任务的逻辑,减少定义多个handler方法。
创建一个定时任务handler
@XxlJob("doJob")
@Transactional(rollbackFor = Exception.class)
public void doJob(){
String jobParam = XxlJobHelper.getJobParam();
try {
if(StrUtil.isNotBlank(jobParam)){
JSONObject jsonObject = JSONObject.parseObject(jobParam);
if(Objects.nonNull(jsonObject)){
Object bean = SpringUtils.getBean(jsonObject.getString("bean"));
Method method = bean.getClass().getMethod(jsonObject.getString("method"));
logger.info("调度定时任务执行开始:{}",jobParam);
method.invoke(bean);
logger.info("调度定时任务执行结束:{}",jobParam);
}
}
}catch (Exception e){
logger.info("调度定时任务执行失败:{},原因是:{}",jobParam,e.getMessage());
XxlJobHelper.handleFail();
}
}
批量新增任务(带参数)
JobHeadler: doJob
任务参数:{"bean":"userService","method":"demoJob"}
bean:为原先定时任务的类,method:为原先定时任务的方法
完整项目的代码:https://github.com/gorylee/learnDemo