您的位置 首页 java

SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

★★★ 建议 星标 我们 ★★★

Java 进阶架构师 星标 ”!这样才不会错过每日进阶架构文章呀。

SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置 SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

2020年Java原创面试题库连载中

【000期】Java最全面试题库思维导图

【020期】JavaSE系列面试题汇总(共18篇)

【028期】JavaWeb系列面试题汇总(共10篇)

【042期】JavaEE系列面试题汇总(共13篇)

【049期】数据库系列面试题汇总(共6篇)

【053期】中间件系列面试题汇总(共3篇)

【065期】数据结构与算法面试题汇总(共11篇)

【076期】分布式面试题汇总(共10篇)

【077期】综合面试题系列(一)

【078期】综合面试题系列(二)

【079期】综合面试题系列(三)

【080期】综合面试题系列(四)

【081期】综合面试题系列(五)

【082期】综合面试题系列(六)

【083期】综合面试题系列(七)

【084期】综合面试题系列(八)

【085期】综合面试题系列(九)

【086期】综合面试题系列(十)

【087期】综合面试题系列(十一)

【088期】综合面试题系列(十二)

【089期】综合面试题系列(十三)

更多内容,点击上面蓝字查看

SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

作者:老爷爷的博客园

来源:老爷爷的博客园

什么是动态配置定时任务?

首先说下这次主题,动态配置。没接触过定时任务的同学可以先看下此篇:JAVA定时任务实现的几种方式

定时任务实现方式千人千种,不过基础的无外乎 1、JDK 的Timer类 2、Quartz 3、 Spring Task 。生产上三种方式我都有使用过。但是使用过程中用的最多的便是xml配置的方式,这种方式最简单,无代码侵入,也比较好理解。

但是却有个致命的缺点,比如你要改某个任务的触发时间,亦或是你要新增一个任务,暂停一个任务。怎么做?

停应用!改XML配置!重新启动!

是不是很致命。最近重新研究了下Quartz的配置,实现了不停机添加、暂停、删除、立即触发任务的方法,在本篇分享出来,其实也不算是完全的研究,在上家公司已经有大佬实现了,这次是也是基于大佬的理解重新实现下。

国际惯例~先看效果图

管理界面:

SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

效果图:实在不知道该跑什么了,每隔十秒打一段话吧。

SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

技术实现

maven依赖

使用springboot做框架支持。

 <!-- quartz --> 
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>

数据表。

 CREATE TABLE `sys_task` ( 
`id` bigint(20) NOT AUTO_INCREMENT,
`job_name` varchar(255) DEFAULT COMMENT '任务名',
`description` varchar(255) DEFAULT COMMENT '任务描述',
`cron_expression` varchar(255) DEFAULT COMMENT 'cron表达式',
`bean_class` varchar(255) DEFAULT COMMENT '任务执行时调用哪个类的方法 包名+类名',
`job_status` varchar(255) DEFAULT COMMENT '任务状态',
`job_group` varchar(255) DEFAULT COMMENT '任务分组',
`create_user` varchar(64) DEFAULT COMMENT '创建者',
`create_time` datetime DEFAULT COMMENT '创建时间',
`update_user` varchar(64) DEFAULT COMMENT '更新者',
`update_time` datetime DEFAULT COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=32 DEFAULT CHARSET=utf8;

实现步骤。

  1. 启动项目,启动task监听

  2. 读取数据库,将开启的任务job和trigger加载到scheduler调度器

  3. 根据任务调度运行job类

  4. 每次运行利用AdaptableJobFactory 实例化 job类,以便注入要运行的service

听着是不是很简单,但却还是一头雾水,且听我慢慢道来~~

代码逻辑。

第一步:启动项目,加载监听。

Quartz配置

Springboot的配置方法,常规Spring项目可以在xml中配置

 @Configuration 
public class QuartzConfigration {

@Autowired
private JobFactory jobFactory;

@Bean
public SchedulerFactoryBean schedulerFactoryBean {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean;
try {
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setQuartzProperties(quartzProperties);
schedulerFactoryBean.setJobFactory(jobFactory);
} catch (Exception e) {
e.printStackTrace;
}
return schedulerFactoryBean;
}
// 指定quartz.properties,可在配置文件中配置相关属性
@Bean
public Properties quartzProperties throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean;
propertiesFactoryBean.setLocation(new ClassPathResource("/config/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet;
return propertiesFactoryBean.getObject;
}
// 创建schedule
@Bean(name = "scheduler")
public Scheduler scheduler {
return schedulerFactoryBean.getScheduler;
}
}

监听器。

 @Component 
@Order(value = 1)
public class ScheduleJobInitListener implements CommandLineRunner {
@Autowired
TaskService scheduleJobService;
@ Override
public void run(String... arg0) throws Exception {
try {
scheduleJobService.initSchedule;
} catch (Exception e) {
e.printStackTrace;
}

}

}

CommandLineRunner类似Spring框架的ApplicationListener监听器。官方的解释是:

第二步:读取数据库,加载scheduler调度器。

job方法。

 @Override 
public void initSchedule throws SchedulerException {
// 这里获取任务信息数据
List<TaskDO> jobList = taskMapper.list;
for (TaskDO task : jobList) {
if (JobStatusEnum.RUNNING.getCode.equals(task.getJobStatus)) {
quartzManager.addJob(task);
}
}
}

添加任务到Quartz调度器。

 /** 
* 添加任务/
@SuppressWarnings("unchecked")
public void addJob(TaskDO task) {
try {
// 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(task.getBeanClass).newInstance
.getClass);
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(task.getJobName, task.getJobGroup)// 任务名称和组构成任务key
.build;
// 定义调度触发规则
// 使用cornTrigger规则
Trigger trigger = TriggerBuilder.newTrigger.withIdentity(task.getJobName, task.getJobGroup)// 触发器 key
.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
.withSchedule(CronScheduleBuilder.cronSchedule(task.getCronExpression)).startNow.build;
// 把作业和触发器注册到任务调度中
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown) {
scheduler.start;
}
} catch (Exception e) {
e.printStackTrace;
}
}

Scheduler作为Quartz的核心调度器,有将近50多个API接口,包括任务的添加,暂停,恢复,删除等一系列的API,这里仅介绍一些常用的,想要了解更多可以稍后看下彩蛋部分。

  1. start方法:只有调用start方法后,Scheduler线程才开始启动触发器trigger,运行job

  2. pauseJob(JobKey jobKey) :根据指定的JobDetail key暂停job。

  3. resumeJob(JobKey jobKey) :根据指定的key恢复一个job。

  4. deleteJob(JobKey jobKey) :删除一个job

  5. triggerJob(JobKey jobKey) :触发一个JobDetail(现在执行)。

  6. rescheduleJob(TriggerKey triggerKey, Trigger newTrigger):

用给定的键删除触发器,并存储新的触发器,它必须与同一个作业相关联(新触发器必须具有指定的作业名和组)-然而,新触发器不必具有与旧触发器相同的名称。

第三步:根据任务调度运行job类。

其实这一步是不需要我们编写的,在我们将正确的JobDetail 和 Trigger 表达式加载到任务调度后,调度器会自动触发任务的执行 。

第四步:实例化job类,注入要运行的service。

工厂类

 @Component 
public class JobFactory extends AdaptableJobFactory {
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
//为什么需要这个类呢,在我写的这个demo中,大家可以将此类删掉,发现程序也可以正确运行,可是我为什么还是加上呢。
//大家可以看下我们的任务类,大家可以看到Job对象的实例化过程是在Quartz中进行的,这时候我们将spring的东西注入进来,肯定是行不通的,所以需要这个类
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;

@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}

任务类。

 @DisallowConcurrentExecution //作业不并发 
@Component
public class HelloWorldJob implements Job {
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println("欢迎使用yyblog,这是一个定时任务 --小卖铺的老爷爷!"+ DateUtils.fullTime(new Date));
}
}

好了,大功告成,一个简单的动态配置的定时任务已经完成。是不是so easy,下面我们再来简单实现下其他的几种常用的api吧。

暂停一个job。

 public void pauseJob(TaskDO task) throws SchedulerException { 
JobKey jobKey = JobKey.jobKey(task.getJobName, task.getJobGroup);
scheduler.pauseJob(jobKey);
}

恢复一个job

 public void resumeJob(TaskDO task) throws SchedulerException { 
JobKey jobKey = JobKey.jobKey(task.getJobName, task.getJobGroup);
scheduler.resumeJob(jobKey);
}

删除一个job

 public void deleteJob(TaskDO task) throws SchedulerException { 
JobKey jobKey = JobKey.jobKey(task.getJobName, task.getJobGroup);
scheduler.deleteJob(jobKey);
}

立即触发job

 public void runJobNow(TaskDO task) throws SchedulerException { 
JobKey jobKey = JobKey.jobKey(task.getJobName, task.getJobGroup);
scheduler.triggerJob(jobKey);
}

更新job表达式

 public void updateJobCron(TaskDO task) throws SchedulerException { 
TriggerKey triggerKey = TriggerKey.triggerKey(task.getJobName, task.getJobGroup);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCronExpression);
trigger = trigger.getTriggerBuilder.withIdentity(triggerKey).withSchedule(scheduleBuilder).build;
scheduler.rescheduleJob(triggerKey, trigger);
}

总结

正文部分基本上就这些,不多废话了,本文没有太多的讲解原理,只是简单的应用。

 

之前,给大家发过 三份Java 面试宝典,这次新增了一份,目前总共是 四份 面试宝典,相信在跳槽前一个月按照面试宝典准备准备,基本没大问题。

  • 《java面试宝典5.0》 (初中级)

  • 《350道Java面试题:整理自100+公司》 (中高级)

  • 《资深java面试宝典-视频版》 (资深)

  • 《Java[BAT]面试必备》 (资深)

分别适用于 初中级,中高级 资深 级工程师 的面试复习。

内容包含 java基础、javaweb、mysql性能优化、JVM、锁、百万并发、消息队列,高性能缓存、反射、Spring全家桶原理、微服务、Zookeeper、数据结构、限流熔断降级等等。

看到这里,证明有所收获

文章来源:智云一二三科技

文章标题:SpringBoot 整合 Quartz 实现 JAVA 定时任务的动态配置

文章地址:https://www.zhihuclub.com/179689.shtml

关于作者: 智云科技

热门文章

网站地图