目录
标签:Quartz.Job.Scheduler;
一、简介
Quartz由Java编写的功能丰富的开源作业调度框架,可以集成到几乎任何Java应用程序中,并且能够创建多个作业调度;
在实际的业务中,有很多场景依赖定时任务,比如常见的:订单超时处理,数据报表统计分析,会员等周期性管理,业务识别和预警通知等;
二、工程搭建
1、工程结构

2、依赖管理
在starter-quartz组件中,实际依赖的是quartz组件2.3.2版本,使用Quartz框架时,需要自定义任务和执行逻辑,以更加灵活的方式管理业务调度;- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-quartz</artifactId>
- <version>${spring-boot.version}</version>
- </dependency>
复制代码 3、数据库
Quartz框架使用的表结构在如图的路径下,本文选择MySQL数据库存储,除此之外自定义两张表:quartz_job任务表和quartz_log任务执行日志表;

4、配置文件
在配置文件中使用Druid组件连接boot-quartz数据库,对于Quartz框架,主要配置数据库存储,调度器的基础信息,以及执行任务的线程池;- spring:
- # 定时器配置
- quartz:
- # 使用数据库存储
- job-store-type: jdbc
- # 初始化完成后自动启动调度程序
- autoStartup: true
- properties:
- org:
- quartz:
- # 调度器配置
- scheduler:
- instanceName: bootQuartzScheduler
- instanceId: AUTO
- # 存储配置
- jobStore:
- class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
- driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
- tablePrefix: qrtz_
- isClustered: true
- misfireThreshold: 12000
- clusterCheckinInterval: 15000
- useProperties: false
- # 线程池配置
- threadPool:
- threadNamePrefix: Boot_Job_Pool
- threadPriority: 5
- threadCount: 10
- class: org.quartz.simpl.SimpleThreadPool
复制代码 三、Quartz用法
对于任务管理的相关Web接口,采用Swagger文档组件,接口和实体类添加注解后,访问IP:Port/swagger-ui/index.html地址即可;

1、初始化加载
在服务启动时执行init初始化方法,查询quartz_job表中运行和暂停状态的任务,判断触发器是否存在,如果不存在则创建,如果存在则更新;- @Service
- public class QuartzJobService {
- @Resource
- private QuartzJobMapper quartzJobMapper ;
- @Resource
- private QuartzManage quartzManage;
- @PostConstruct
- public void init () {
- LambdaQueryWrapper<QuartzJob> queryWrapper = new LambdaQueryWrapper<>() ;
- queryWrapper.in(QuartzJob::getState,JobState.JOB_RUN.getStatus(),JobState.JOB_STOP.getStatus());
- List<QuartzJob> jobList = quartzJobMapper.selectList(queryWrapper);
- jobList.forEach(quartzJob -> {
- CronTrigger cronTrigger = quartzManage.getCronTrigger(quartzJob.getId()) ;
- if (Objects.isNull(cronTrigger)){
- quartzManage.createJob(quartzJob);
- } else {
- quartzManage.updateJob(quartzJob);
- }
- });
- }
- }
复制代码 2、新增任务
在创建任务时,需要定义JobKey和TriggerKey的构建规则,Key需要具备唯一性,通常使用任务表的主键ID,任务一般是基于Cron表达式被调度执行的;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
- public void createJob (QuartzJob quartzJob){
- try {
- // 构建任务
- JobDetail jobDetail = JobBuilder.newJob(QuartzRecord.class).withIdentity(getJobKey(quartzJob.getId())).build() ;
- // 构建Cron调度器
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
- .cronSchedule(quartzJob.getCronExpres())
- .withMisfireHandlingInstructionDoNothing() ;
- // 任务触发器
- CronTrigger trigger = TriggerBuilder.newTrigger()
- .withIdentity(getTriggerKey(quartzJob.getId()))
- .withSchedule(scheduleBuilder).build() ;
- jobDetail.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY,quartzJob);
- scheduler.scheduleJob(jobDetail,trigger) ;
- // 状态校验
- checkStop(quartzJob) ;
- } catch (SchedulerException e){
- throw new RuntimeException("createJob Fail",e) ;
- }
- }
- }
复制代码 3、更新任务
先通过任务ID查询TriggerKey,对于更新来说,最常见的就是Cron表达式即调度规则的更新,或者任务的执行参数更新;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
- public void updateJob(QuartzJob quartzJob) {
- try {
- // 查询触发器Key
- TriggerKey triggerKey = getTriggerKey(quartzJob.getId());
- // 构建Cron调度器
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder
- .cronSchedule(quartzJob.getCronExpres())
- .withMisfireHandlingInstructionDoNothing();
- // 任务触发器
- CronTrigger trigger = getCronTrigger(quartzJob.getId())
- .getTriggerBuilder().withIdentity(triggerKey)
- .withSchedule(scheduleBuilder).build();
- trigger.getJobDataMap().put(QuartzJob.JOB_PARAM_KEY, quartzJob);
- scheduler.rescheduleJob(triggerKey, trigger);
- // 状态校验
- checkStop(quartzJob) ;
- } catch (SchedulerException e) {
- throw new RuntimeException("updateJob Fail",e) ;
- }
- }
- }
复制代码 4、暂停任务
先通过任务ID查询JobKey,判断任务是非运行状态,则停止任务;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
- public void checkStop (QuartzJob quartzJob){
- try {
- if(quartzJob.getState() != JobState.JOB_RUN.getStatus()){
- this.scheduler.pauseJob(getJobKey(quartzJob.getId()));
- }
- } catch (SchedulerException e){
- throw new RuntimeException("pauseJob Fail",e) ;
- }
- }
- }
复制代码 5、恢复任务
先通过任务ID查询JobKey,恢复任务正常执行;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
- public void resumeJob (Integer jobId){
- try {
- this.scheduler.resumeJob(getJobKey(jobId));
- } catch (SchedulerException e){
- throw new RuntimeException("resumeJob Fail",e) ;
- }
- }
- }
复制代码 6、执行一次
传入任务主体,再通过任务ID查询JobKey,然后立即执行一次任务;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
-
- public void run (QuartzJob quartzJob){
- try {
- JobDataMap dataMap = new JobDataMap() ;
- dataMap.put(QuartzJob.JOB_PARAM_KEY,quartzJob);
- this.scheduler.triggerJob(getJobKey(quartzJob.getId()),dataMap);
- } catch (SchedulerException e){
- throw new RuntimeException("run Fail",e) ;
- }
- }
- }
复制代码 7、删除任务
先通过任务ID查询JobKey,彻底删除任务;- @Component
- public class QuartzManage {
- @Resource
- private Scheduler scheduler ;
- public void deleteJob (Integer jobId){
- try {
- scheduler.deleteJob(getJobKey(jobId));
- } catch (SchedulerException e){
- throw new RuntimeException("deleteJob Fail",e) ;
- }
- }
- }
复制代码 8、任务执行
Quartz被集成在Spring框架之后,任务类自然会以Bean对象的方式被管理,在任务创建时,设置要执行的作业类QuartzRecord,该类继承QuartzJobBean抽象类,通过重写executeInternal方法,来管理任务实际执行的逻辑;- public class QuartzRecord extends QuartzJobBean {
- @Override
- protected void executeInternal(JobExecutionContext context) {
- QuartzJob quartzJob = (QuartzJob)context.getMergedJobDataMap().get(QuartzJob.JOB_PARAM_KEY) ;
- QuartzLogService quartzLogService = (QuartzLogService)SpringContextUtil.getBean("quartzLogService") ;
- // 定时器日志记录
- QuartzLog quartzLog = new QuartzLog () ;
- quartzLog.setJobId(quartzJob.getId());
- quartzLog.setBeanName(quartzJob.getBeanName());
- quartzLog.setParams(quartzJob.getParams());
- quartzLog.setCreateTime(new Date());
- long beginTime = System.currentTimeMillis() ;
- try {
- // 加载并执行
- Object target = SpringContextUtil.getBean(quartzJob.getBeanName());
- Method method = target.getClass().getDeclaredMethod("run", String.class);
- method.invoke(target, quartzJob.getParams());
- long executeTime = System.currentTimeMillis() - beginTime;
- quartzLog.setTimes((int)executeTime);
- quartzLog.setState(LogState.LOG_SUS.getStatus());
- } catch (Exception e){
- // 异常信息
- long executeTime = System.currentTimeMillis() - beginTime;
- quartzLog.setTimes((int)executeTime);
- quartzLog.setState(LogState.LOG_FAIL.getStatus());
- quartzLog.setError(e.getMessage());
- } finally {
- // 保存执行日志
- quartzLogService.insert(quartzLog) ;
- }
- }
- }
复制代码 四、参考源码
- 文档仓库:
- https://gitee.com/cicadasmile/butte-java-note
- 源码仓库:
- https://gitee.com/cicadasmile/butte-spring-parent
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |