文章目录
- 前言
- 定时任务实现方式
-
- Timer
- ScheduledExecutorService
- [Spring Task](#Spring Task)
- Quartz
- 以上定时任务存在的问题
- 解决方案XXL-JOB
- 代码案例

前言
XXL-JOB 是一款分布式任务调度框架,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。基于 Java 语言实现,主要用于解决分布式系统中任务调度的一致性、可靠性和可扩展性问题。它具有轻量级、易集成、功能丰富等特点,广泛应用于微服务、分布式系统中的定时任务、批量处理、数据同步等场景。
官网:https://www.xuxueli.com/xxl-job/
定时任务实现方式
Timer
java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少
ScheduledExecutorService
jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。
Spring Task
Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。
Quartz
之前用的比较多,配置起来复杂,不支持分片,没用界面。
以上定时任务存在的问题
1.执行一次
如果想让它马上执行一次,这个时候可能就需要额外再写一个Rest接口或者再另外写一个单独的Job
2.更改执行时间
得修改代码,提交测试,然后打包上线
3.暂停任务
比如一些定时报警的需求,当报警突然变得很多,这个时候需要暂停一下让其停止发送警。
我们可以用配置的开关去做,再逻辑中判断定时任务开关是否打开来做。这样做虽然也比较简单,但是我们这样需要新添加一些与任务无关的逻辑
4.监控
没有管理界面,不方便查看任务执行情况
5.分片执行
单台服务处理大数据量数据时间太长、效率低下,需要其他机器协同执行
解决方案XXL-JOB
支持任务分片
文档完善
提供管理台
接入简单
弹性扩容
...
分片原理

架构图

代码案例
1.git拉去代码
GitHub: https://github.com/xuxueli/xxl-job
Gitee: https://gitee.com/xuxueli0323/xxl-job/
2.数据库表初始化
执行以下sql文件
3.启动xxl-job-admin项目
修改数据库连接相关配置
启动成功后进入前台
127.0.0.1:8080/xxl-job-admin
admin/123456
4.搭建demo
启动xxl-job-executor-sample-springboot或新建一个demo
1.pom依赖
xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>com.xuxueli</groupId>
<artifactId>xxl-job-core</artifactId>
<version>2.2.0</version>
</dependency>
</dependencies>
2.配置文件
yml
server:
port: 8190
servlet:
context-path: /lc
spring:
application:
name: qf-xxl-job-demo0
xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
accessToken: default_token
executor:
appname: qf-xxl-job-demo
address: ""
ip: 127.0.0.1
port: 9910
logpath: D:\files\log
logretentiondays: 10
如果想要实现集群下执行定时任务,需要配置不同的xxl.job.executor.port和spring.application.name。但是注意需要配置相同的xxl.job.executor.appname。
如:
xml
server:
port: 8191
servlet:
context-path: /
spring:
application:
name: qf-xxl-job-demo1
xxl:
job:
admin:
addresses: http://127.0.0.1:8080/xxl-job-admin
accessToken: default_token
executor:
appname: qf-xxl-job-demo
address: ""
ip: 127.0.0.1
port: 9911
logpath: D:\files\log
logretentiondays: 10
3.配置类
java
import com.xxl.job.core.executor.impl.XxlJobSpringExecutor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* xxl-job config
*
* @author xuxueli 2017-04-28
*/
@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.admin.timeout}")
// private int timeout;
@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.setTimeout(timeout);
xxlJobSpringExecutor.setLogPath(logPath);
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
return xxlJobSpringExecutor;
}
/**
* 针对多网卡、容器内部署等情况,可借助 "spring-cloud-commons" 提供的 "InetUtils" 组件灵活定制注册IP;
*
* 1、引入依赖:
* <dependency>
* <groupId>org.springframework.cloud</groupId>
* <artifactId>spring-cloud-commons</artifactId>
* <version>${version}</version>
* </dependency>
*
* 2、配置文件,或者容器启动变量
* spring.cloud.inetutils.preferred-networks: 'xxx.xxx.xxx.'
*
* 3、获取IP
* String ip_ = inetUtils.findFirstNonLoopbackHostInfo().getIpAddress();
*/
}
4.启动类
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class XxlJobApplication {
public static void main(String[] args) {
SpringApplication.run(XxlJobApplication.class, args);
}
}
5.任务
java
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;
import com.xxl.job.core.util.ShardingUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class TestJob {
@XxlJob("helloWorld")
public ReturnT<String> helloWorld(String param) {
ShardingUtil.ShardingVO shardingVo = ShardingUtil.getShardingVo();
int total = shardingVo.getTotal();//分片总数
int index = shardingVo.getIndex();//当前分片索引
log.info("分片总数:{},当前分片索引:{}",total,index);
XxlJobLogger.log("XXL-JOB, updateSilentExecStatus beginning");
System.out.println("XXL-JOB===============================Hello World-0,param"+param);
return ReturnT.SUCCESS;
}
/**
* 5、生命周期任务示例:任务初始化与销毁时,支持自定义相关逻辑;
*/
@XxlJob(value = "demoJobHandler2", init = "init", destroy = "destroy")
public ReturnT<String> demoJobHandler2(String param) throws Exception {
log.info("XXL-JOB, Hello World.");
return ReturnT.SUCCESS;
}
public void init(){
log.info("init");
}
public void destroy(){
log.info("destroy");
}
}
启动项目
6.新增执行器
AppName就是在配置文件中的xxl.job.executor.appname = qf-xxl-job-demo
启动项目后可以在执行器管理看到对应的服务

7.创建任务
当执行器注册成功后创建任务
- 执行器:选择我们刚上一步创建的执行器。
- 任务描述: 随便写下这个任务主要是做什么的。
- 负责人:测试环境就只有一个admin可选,生产环境可指定具体的负责人。
- 调度类型: 选择默认CRON,其他还有一个无和固定速度,顾名思义无就是不执行,固定速度就是每隔多少秒就执行一次。
- Cron: cron表达式,不知道怎么写的可以点击右边的编辑按钮,直接选择时间。
- 运行模式:分为BEAN和GLUE两种,BEAN就是javabean,自定义执行函数,GLUE就是将任务代码直接"贴到"调度系统中执行。这里我们选择默认的BEAN即可,在业务代码中实现具体逻辑。
- JobHandler: 具体要执行的任务函数。
- 任务参数:下发到执行器任务函数的参数,这里我们可以填写一些需要发送的用户和内容。
添加完之后在操作点击启动,即可执行定时任务