引入 Quartz 依赖
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
|
application.yml 配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| spring: datasource: driver-class-name: org.postgresql.Driver url: jdbc:postgresql://localhost:5432/public_opinion_db?useUnicode=true&characterEncoding=UTF-8 username: postgres password: 123456 quartz: job-store-type: jdbc auto-startup: true startup-delay: 0 wait-for-jobs-to-complete-on-shutdown: true overwrite-existing-jobs: false scheduler-name: PublicOpinionScheduler jdbc: initialize-schema: never properties: org: quartz: jobStore: class: org.springframework.scheduling.quartz.LocalDataSourceJobStore driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate tablePrefix: quartz.QRTZ_ isClustered: true useProperties: false scheduler: instanceName: PublicOpinionScheduler instanceId: AUTO threadPool: threadCount: 25 threadPriority: 5 class: org.quartz.simpl.SimpleThreadPool
mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true mapper-locations: classpath*:/mapper/**/*.xml
|
初始化 Quartz 数据库表
脚本在 ~/.m2/repository/org/quartz-scheduler/quartz/2.3.2/quartz-2.3.2.jar!/org/quartz/impl/jdbcjobstore
定时任务示例
可以实现 Job:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Slf4j @Component @RequiredArgsConstructor public class FisrtlJob implements Job {
private final XxxService xxxService;
@Override public void execute(JobExecutionContext context) { ... }
}
|
也可以继承 QuartzJobBean:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class SecondJob extends QuartzJobBean {
private String name;
public void setName(String name) { this.name = name; }
@Override protected void executeInternal(JobExecutionContext context) { System.out.println(name); } }
|
Spring 的 QuartzJobBean 支持把 JobDataMap 中的属性注入到 Job。
例如:
1 2 3 4
| JobDetail jobDetail = JobBuilder .newJob(MyJob.class) .usingJobData("name", "test") .build();
|
创建 JobDetail 和 Trigger
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @Configuration public class fisrtQuartzConfig {
@Value("${quartz.jobs.fisrt-job.cron:0 0/5 * * * ?}") private String cron;
@Value("${quartz.jobs.fisrt-job.description:0 0/5 * * * ?}") private String description;
@Bean public JobDetail fisrtJobDetail() { return JobBuilder.newJob(FisrtlJob.class) .withIdentity(JobConstants.FIRST_JOB, JobConstants.FIRST_GROUP) .withDescription(description) .storeDurably() .build(); }
@Bean public Trigger fisrtTrigger(JobDetail fisrtJobDetail) { CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron); return TriggerBuilder.newTrigger() .forJob(fisrtJobDetail) .withIdentity(JobConstants.FISRT_JOB, JobConstants.FISRT_GROUP) .withSchedule(scheduleBuilder) .build(); }
}
|
附赠一个 “把 Quartz 的管理封装成 Service”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public interface QuartzTaskService {
List<QuartzJobInfoVO> listJobs();
QuartzJobInfoVO getJob(String jobName, String groupName);
void resumeJob(String jobName, String groupName);
void pauseJob(String jobName, String groupName);
void updateCron(String jobName, String groupName, String cronExpression);
void runOnce(String jobName, String groupName);
void deleteJob(String jobName, String groupName);
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
| @Service @RequiredArgsConstructor public class QuartzTaskServiceImpl implements QuartzTaskService {
private final Scheduler scheduler;
@Override @SneakyThrows public List<QuartzJobInfoVO> listJobs() { List<QuartzJobInfoVO> result = new ArrayList<>(); for (String group : scheduler.getJobGroupNames()) { for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.jobGroupEquals(group))) { result.add(buildJobInfo(jobKey)); } } return result; }
@Override @SneakyThrows public QuartzJobInfoVO getJob(String jobName, String groupName) { return buildJobInfo(new JobKey(jobName, groupName)); }
@Override @SneakyThrows public void resumeJob(String jobName, String groupName) { scheduler.resumeJob(JobKey.jobKey(jobName, groupName)); }
@Override @SneakyThrows public void pauseJob(String jobName, String groupName) { scheduler.pauseJob(JobKey.jobKey(jobName, groupName)); }
@Override @SneakyThrows public void updateCron(String jobName, String groupName, String cronExpression) { TriggerKey triggerKey = new TriggerKey(jobName, groupName);
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); if (oldTrigger == null) throw new IllegalArgumentException("任务不存在");
CronTrigger newTrigger = oldTrigger.getTriggerBuilder() .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression) .withMisfireHandlingInstructionDoNothing()) .build(); scheduler.rescheduleJob(triggerKey, newTrigger); }
@Override @SneakyThrows public void runOnce(String jobName, String groupName) { scheduler.triggerJob(JobKey.jobKey(jobName, groupName)); }
@Override @SneakyThrows public void deleteJob(String jobName, String groupName) { scheduler.deleteJob(JobKey.jobKey(jobName, groupName)); }
private QuartzJobInfoVO buildJobInfo(JobKey jobKey) throws SchedulerException { JobDetail detail = scheduler.getJobDetail(jobKey); List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
QuartzJobInfoVO info = new QuartzJobInfoVO(); info.setJobName(jobKey.getName()); info.setJobGroup(jobKey.getGroup()); info.setDescription(detail != null ? detail.getDescription() : ""); info.setJobClass(detail != null ? detail.getJobClass().getSimpleName() : "");
if (!triggers.isEmpty()) { Trigger trigger = triggers.get(0); Trigger.TriggerState state = scheduler.getTriggerState(trigger.getKey()); info.setTriggerState(state.name()); info.setNextFireTime(trigger.getNextFireTime()); info.setPreviousFireTime(trigger.getPreviousFireTime()); if (trigger instanceof CronTrigger cronTrigger) { info.setCronExpression(cronTrigger.getCronExpression()); } } else { info.setTriggerState("NO_TRIGGER"); info.setCronExpression(""); } return info; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Data @Schema(description = "Quartz 任务信息视图对象") public class QuartzJobInfoVO {
@Schema(description = "任务名称") private String jobName;
@Schema(description = "任务分组") private String jobGroup;
@Schema(description = "任务描述") private String description;
@Schema(description = "任务类名") private String jobClass;
@Schema(description = "触发器状态") private String triggerState;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Schema(description = "下次触发时间") private Date nextFireTime;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @Schema(description = "上次触发时间") private Date previousFireTime;
@Schema(description = "Cron 表达式") private String cronExpression; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| @Slf4j @Tag(name = "定时任务管理", description = "基于 Quartz 的定时任务管理接口") @RestController @RequestMapping("/quartz") @RequiredArgsConstructor public class QuartzAdminController {
private final QuartzTaskService quartzTaskService;
@Operation(summary = "查询 Job 列表") @GetMapping("/jobs") public R<List<QuartzJobInfoVO>> listJobs() { List<QuartzJobInfoVO> vos = quartzTaskService.listJobs(); return R.ok(vos); }
@Operation(summary = "查询 Job 详情") @GetMapping("/jobs/{group}/{name}") public R<QuartzJobInfoVO> getJob(@PathVariable String group, @PathVariable String name) { QuartzJobInfoVO vo = quartzTaskService.getJob(name, group); return R.ok(vo); }
@Operation(summary = "暂停任务") @PostMapping("/jobs/{group}/{name}/pause") public R<Void> pauseJob(@PathVariable String group, @PathVariable String name) { quartzTaskService.pauseJob(name, group); return R.ok(); }
@Operation(summary = "恢复任务") @PostMapping("/jobs/{group}/{name}/resume") public R<Void> resumeJob(@PathVariable String group, @PathVariable String name) { quartzTaskService.resumeJob(name, group); return R.ok(); }
@Operation(summary = "立即触发任务") @PostMapping("/jobs/{group}/{name}/trigger") public R<Void> triggerJob(@PathVariable String group, @PathVariable String name) { quartzTaskService.runOnce(name, group); return R.ok(); }
@Operation(summary = "更新 Cron 表达式") @PutMapping("/jobs/{group}/{name}/cron") public R<Void> updateCron(@PathVariable String group, @PathVariable String name, @RequestParam String cron) { if (!CronExpression.isValidExpression(cron)) throw new IllegalArgumentException("无效的 Cron 表达式: " + cron);
quartzTaskService.updateCron(name, group, cron); return R.ok(); }
}
|
参考阅读
https://www.cnblogs.com/summerday152/p/14193968.html