Contents
spring项目中经常用到定时任务,
@Scheduled 定时任务
1@Component
2public class ScheduledTest {
3 /**
4 * 定时任务
5 */
6 @Scheduled(cron = "")
7 public void scheduledTest() {
8 System.out.println("定时开始 " + new Date());
9 }
10}
11
cron 解释
cron表达式是一个字符串,分为6或7个域,每两个域之间用空格分隔,其语法格式为:
"秒域 分域 时域 日域 月域 周域 年域"
其中,年域可以省略,省略时表示每年。
定时任务启用
在启动类上添加@EnableScheduling
开启定时任务
常用 cron 表达式
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
cron 表达式在线生成 https://www.bejson.com/othertools/cron/
Quartz
介绍
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,Quartz是一个完全由java编写的开源作业调度框架。
使用
Quartz的基本组成部分:
调度器:Scheduler
任务:JobDetail
触发器:Trigger,包括SimpleTrigger和CronTrigger
springboot Demo
1<dependency>
2 <groupId>org.springframework.boot</groupId>
3 <artifactId>spring-boot-starter-quartz</artifactId>
4 </dependency>
5
创建job
1
2import org.quartz.Job;
3import org.quartz.JobExecutionContext;
4import org.quartz.JobExecutionException;
5
6public class HelloJob implements Job {
7 @Override
8 public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
9 System.out.println("hello job");
10 }
11}
12
创建Schedule
1
2import org.quartz.*;
3import org.quartz.impl.StdSchedulerFactory;
4
5import java.util.concurrent.TimeUnit;
6
7public class MyQuartz {
8 public static void main(String[] args) throws SchedulerException, InterruptedException {
9 // 1、创建调度器Scheduler
10 SchedulerFactory schedulerFactory = new StdSchedulerFactory();
11 Scheduler scheduler = schedulerFactory.getScheduler();
12 // 2、创建JobDetail实例
13 JobDetail jobDetail = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();
14
15 // 3、构建Trigger实例,每隔1s执行一次
16 Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1")
17 .startNow()
18 .withSchedule(SimpleScheduleBuilder.simpleSchedule()
19 //每隔1s执行一次
20 .withIntervalInSeconds(1)
21 //一直执行
22 .repeatForever()).build();
23 //4、执行
24 scheduler.scheduleJob(jobDetail, trigger);
25 System.out.println("--------scheduler start ! ------------");
26 scheduler.start();
27 //睡眠
28 TimeUnit.MINUTES.sleep(1);
29 scheduler.shutdown();
30 System.out.println("--------scheduler shutdown ! ------------");
31 }
32}
33
配置
1server:
2 port: 8080
3spring:
4 datasource:
5 url: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
6 username: root
7 password: 123456
8 driver-class-name: com.mysql.cj.jdbc.Driver
9 type: com.zaxxer.hikari.HikariDataSource
10 hikari:
11 minimum-idle: 5
12 connection-test-query: SELECT 1 FROM DUAL
13 maximum-pool-size: 20
14 auto-commit: true
15 idle-timeout: 30000
16 pool-name: SpringBootDemoHikariCP
17 max-lifetime: 60000
18 connection-timeout: 30000
19 quartz:
20 # 参见 org.springframework.boot.autoconfigure.quartz.QuartzProperties
21 job-store-type: jdbc
22 wait-for-jobs-to-complete-on-shutdown: true
23 scheduler-name: SpringBootDemoScheduler
24 properties:
25 org.quartz.threadPool.threadCount: 5
26 org.quartz.threadPool.threadPriority: 5
27 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true
28 org.quartz.jobStore.misfireThreshold: 5000
29 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX
30 org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
31 # 在调度流程的第一步,也就是拉取待即将触发的triggers时,是上锁的状态,即不会同时存在多个线程拉取到相同的trigger的情况,也就避免的重复调度的危险。参考:https://segmentfault.com/a/1190000015492260
32 org.quartz.jobStore.acquireTriggersWithinLock: true
33logging:
34 level:
35 com.example.demo: debug
36 org.quartz: debug
37
38
1@Service
2@Slf4j
3public class JobServiceImpl implements JobService {
4 private final Scheduler scheduler;
5 private final JobMapper jobMapper;
6
7 @Autowired
8 public JobServiceImpl(Scheduler scheduler, JobMapper jobMapper) {
9 this.scheduler = scheduler;
10 this.jobMapper = jobMapper;
11 }
12
13 /**
14 * 添加并启动定时任务
15 *
16 * @param form 表单参数 {@link JobForm}
17 * @return {@link JobDetail}
18 * @throws Exception 异常
19 */
20 @Override
21 public void addJob(JobForm form) throws Exception {
22 // 启动调度器
23 scheduler.start();
24
25 // 构建Job信息
26 JobDetail jobDetail = JobBuilder.newJob(JobUtil.getClass(form.getJobClassName()).getClass()).withIdentity(form.getJobClassName(), form.getJobGroupName()).build();
27
28 // Cron表达式调度构建器(即任务执行的时间)
29 CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getCronExpression());
30
31 //根据Cron表达式构建一个Trigger
32 CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(form.getJobClassName(), form.getJobGroupName()).withSchedule(cron).build();
33
34 try {
35 scheduler.scheduleJob(jobDetail, trigger);
36 } catch (SchedulerException e) {
37 log.error("【定时任务】创建失败!", e);
38 throw new Exception("【定时任务】创建失败!");
39 }
40
41 }
42
43 /**
44 * 删除定时任务
45 *
46 * @param form 表单参数 {@link JobForm}
47 * @throws SchedulerException 异常
48 */
49 @Override
50 public void deleteJob(JobForm form) throws SchedulerException {
51 scheduler.pauseTrigger(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));
52 scheduler.unscheduleJob(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));
53 scheduler.deleteJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
54 }
55
56 /**
57 * 暂停定时任务
58 *
59 * @param form 表单参数 {@link JobForm}
60 * @throws SchedulerException 异常
61 */
62 @Override
63 public void pauseJob(JobForm form) throws SchedulerException {
64 scheduler.pauseJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
65 }
66
67 /**
68 * 恢复定时任务
69 *
70 * @param form 表单参数 {@link JobForm}
71 * @throws SchedulerException 异常
72 */
73 @Override
74 public void resumeJob(JobForm form) throws SchedulerException {
75 scheduler.resumeJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));
76 }
77
78 /**
79 * 重新配置定时任务
80 *
81 * @param form 表单参数 {@link JobForm}
82 * @throws Exception 异常
83 */
84 @Override
85 public void cronJob(JobForm form) throws Exception {
86 try {
87 TriggerKey triggerKey = TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName());
88 // 表达式调度构建器
89 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(form.getCronExpression());
90
91 CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
92
93 // 根据Cron表达式构建一个Trigger
94 trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
95
96 // 按新的trigger重新设置job执行
97 scheduler.rescheduleJob(triggerKey, trigger);
98 } catch (SchedulerException e) {
99 log.error("【定时任务】更新失败!", e);
100 throw new Exception("【定时任务】创建失败!");
101 }
102 }
103
104 /**
105 * 查询定时任务列表
106 *
107 * @param currentPage 当前页
108 * @param pageSize 每页条数
109 * @return 定时任务列表
110 */
111 @Override
112 public PageInfo<JobAndTrigger> list(Integer currentPage, Integer pageSize) {
113 PageHelper.startPage(currentPage, pageSize);
114 List<JobAndTrigger> list = jobMapper.list();
115 return new PageInfo<>(list);
116 }
117}
118