1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Springboot2 Quartz实现JAVA定时任务的动态配置

Springboot2 Quartz实现JAVA定时任务的动态配置

时间:2022-02-21 18:52:46

相关推荐

Springboot2 Quartz实现JAVA定时任务的动态配置

动态配置Quartz。没接触过定时任务的同学可以先看下此篇:JAVA定时任务实现的几种方式

文章目录

一、需求背景1. 问题现象2. 问题分析3. 解决方案二、需求背景2.1. maven依赖2.2. 创建一个任务表2.3. 实现步骤三、代码逻辑3.1. Quartz配置3.2. 启动项目,加载监听3.3. 读取数据库,加载scheduler调度器3.4. 添加任务到Quartz调度器3.5. 根据任务调度运行job类3.6. 实例化job类,注入要运行的service四、常见的Quartz的API4.1. 新增一个job4.2. 暂停一个job4.2. 删除一个job4.3. 暂停一个job4.4. 立即执行一个job4.5. 更新job表达式五、源码下载和运行5.1. 源码地址5.2. 源码下载5.3. 项目运行
一、需求背景
1. 问题现象

定时任务实现方式: 1.JDK 的Timer类 2.Quartz 3.SpringTask 。

生产上三种方式我都有使用过。但是使用过程中用的最多的便是xml配置的方式,这种方式最简单,无代码侵入,也比较好理解。但是却有个致命的缺点,比如你要改某个任务的触发时间,亦或是你要新增一个任务,暂停一个任务。怎么做?

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

怎样解决上述致命的问题现象呢?

2. 问题分析

请大家想一想:停应用、修改XML配置!重新启动是为了什么?

应该是首先修改Quartz的配置文件,然后,修改一些属性配置参数,最后重新启动项目加载配置文件,对吧!

哪怎样可以动态配置Quartz的配置文件的呢?

3. 解决方案

哪怎样动态配置Quartz的属性参数的呢?如果把Quartz需要的重点关键参数存到数据库,通过页面就可以修改Quartz的属性参数了,对吧!

那问题又来了,属性参数修改了,那有怎样让属性参数生效呢?

其实Quartz官方提供了一些日常操作的API接口方法,只需要咱们把需要的参数传递给对应的api接口即可,因此,咱们的思路,应该这样想,操作增增加定时任务就找Quartz的增加api,传参数,其他的一样,对吧!

既然思路有了,那咱们就应该提前去做以下几件事:

1.Quartz常见的api在哪?或者说在哪里可以找到

2.找出常见的Quartz的api

3.认真分析常见的Quartz的api需要怎样才能触发

温馨建议:

自己写一个demo或者main方法单元测试一下,效果最好,不断完善

举个例子:

增加定时任务,一般需要几个或者什么参数,提前弄明白

这样就可以动态不停应用通过Quartz实现了不停机添加、暂停、删除、立即触发任务的方法

二、需求背景
2.1. maven依赖

<!-- 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>

2.2. 创建一个任务表

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

2.3. 实现步骤

①启动项目,启动task监听

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

③根据任务调度运行job类

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

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

三、代码逻辑
3.1. Quartz配置

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

@Configurationpublic class QuartzConfigration {@Autowiredprivate JobFactory jobFactory;@Beanpublic 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,可在配置文件中配置相关属性@Beanpublic 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();}}

3.2. 启动项目,加载监听

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

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

Interface used to indicate that a bean should run when it is contained within a SpringApplication. Multiple CommandLineRunner beans can be defined within the same application context and can be ordered using the Ordered interface or Order @Order annotation.

接口被用作将其加入spring容器中时执行其run方法。多个CommandLineRunner可以被同时执行在同一个spring上下文中并且执行顺序是以order注解的参数顺序一致。

3.3. 读取数据库,加载scheduler调度器

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

3.4. 添加任务到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):

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

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

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

3.6. 实例化job类,注入要运行的service

工厂类

@Componentpublic class JobFactory extends AdaptableJobFactory {//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.//为什么需要这个类呢,在我写的这个demo中,大家可以将此类删掉,发现程序也可以正确运行,可是我为什么还是加上呢。//大家可以看下我们的任务类,大家可以看到Job对象的实例化过程是在Quartz中进行的,这时候我们将spring的东西注入进来,肯定是行不通的,所以需要这个类@Autowiredprivate AutowireCapableBeanFactory capableBeanFactory;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {//调用父类的方法Object jobInstance = super.createJobInstance(bundle);//进行注入capableBeanFactory.autowireBean(jobInstance);return jobInstance;}}

任务类

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

好了,大功告成,一个简单的动态配置的定时任务已经完成。是不是so easy!

下面我们再来简单实现下其他的几种常用的api吧。

四、常见的Quartz的API
4.1. 新增一个job

/*** 添加任务* * @param scheduleJob* @throws SchedulerException*/ @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();}}

4.2. 暂停一个job

/*** 暂停一个job* * @param task* @throws SchedulerException*/public void pauseJob(TaskDO task) throws SchedulerException {JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());scheduler.pauseJob(jobKey);}

4.2. 删除一个job

/*** 删除一个job* * @param task* @throws SchedulerException*/public void deleteJob(TaskDO task) throws SchedulerException {JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());scheduler.deleteJob(jobKey);}

4.3. 暂停一个job

在这里插入代码片

4.4. 立即执行一个job

/*** 立即执行job* * @param task* @throws SchedulerException*/public void runJobNow(TaskDO task) throws SchedulerException {JobKey jobKey = JobKey.jobKey(task.getJobName(), task.getJobGroup());scheduler.triggerJob(jobKey);}

4.5. 更新job表达式

/*** 更新job时间表达式* * @param task* @throws SchedulerException*/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);}

五、源码下载和运行
5.1. 源码地址

/gb_90/yyblog

5.2. 源码下载

git clone git@:gb_90/yyblog.git

5.3. 项目运行

#1.进入下载的项目目录cd yyblog#2.切换分支到1.0git checkout 1.0#3.初始化数据库(sql在lib下面)#4.修改数据库连接(application.yml)#5.启动项目链接:http://localhost:8080账号:admin密码:123456

Quartz文档地址:/allanzhuo/yyblog/tree/master/doc

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。