Quartz实现JAVA定时杏彩平台出租任务的动态配置

先说点无关杏彩平台出租QQ2952777280【话仙源码论坛】hxforum.com【木瓜源码论坛】papayabbs.com 本文的问题,这段时间特别的不爽,可能有些同学也遇到过。其实也可以说是小事一桩,但感觉也是不容忽视的。我刚毕业时的公司,每个人每次提交代码都有着严格的规范,像table和space的缩进都有严格的要求,可以说你不遵守开发规范就相当于线上bug问题,还是比较严重的。现在发现外面的公司真的是没那么重视这个不重要却又特别重要的问题啊,啊啊啊啊啊啊!!!

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

定时任务实现方式千人千种,不过基础的无外乎 1、JDK 的Timer类 2、Quartz 3、SpringTask 。生产上三种方式我都有使用过。但是使用过程中用的最多的便是xml配置的方式,这种方式最简单,无代码侵入,也比较好理解。
但是却有个致命的缺点,比如你要改某个任务的触发时间,亦或是你要新增一个任务,暂停一个任务。怎么做?
停应用!改XML配置!重新启动!
是不是很致命。最近重新研究了下Quartz的配置,实现了不停机添加、暂停、删除、立即触发任务的方法,在本篇分享出来,其实也不算是完全的研究,在上家公司已经有大佬实现了,这次是也是基于大佬的理解重新实现下。

国际惯例~先看效果图 ps:文末有彩蛋哦~~
管理界面:

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

技术实现
maven依赖
使用springboot做框架支持

复制代码

org.quartz-scheduler
quartz
2.2.1

org.springframework
spring-context-support

复制代码
数据表
复制代码
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;
复制代码
实现步骤
①启动项目,启动task监听
②读取数据库,将开启的任务job和trigger加载到scheduler调度器
③根据任务调度运行job类
④每次运行利用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监听器。官方的解释是:
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注解的参数顺序一致。
第二步:读取数据库,加载scheduler调度器
job方法
复制代码
@Override
public void initSchedule() throws SchedulerException {
// 这里获取任务信息数据
List 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 jobClass = (Class) (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);
}
复制代码
彩蛋部分~
好了,正文部分基本上就这些,不多废话了,本文没有太多的讲解原理,只是简单的应用,水平不够还望大家见谅。
看了上面的效果图是不是还是有种看的见摸不着的感觉,老爷爷这里也做了个线上的实例供大家体验~有兴趣的同学可以亲自试验一下。

原文地址:http://blog.51cto.com/13888952/2150508

时间: 2024-08-11 15:03:25

Quartz实现JAVA定时杏彩平台出租任务的动态配置的相关文章

杏彩平台出租mysql存储过程之遍历多表记录后插入第三方表中

自从学过存储过程后杏彩平台出租(www.1159880099.com )QQ1159880099,就再也没有碰过存储过程,这是毕业后写的第一个存储过程. 因为项目里设备的种类比较多,分别存在不同的数据表中,java中对应不同的java bean对象,想要统一管理有点困难.最近正好要开发一个功能模块,就是需要统一对设备进行处理,想着为了以后都能方便的统一处理各种设备,就从现在开始设计一套方案管理起这些项目吧. 如何统一管理呢? 如果从项目一开始设计的时候就能考虑到项目会发展成今天这样,当初就应该抽

Python中 sys.argv[]的杏彩平台出租用法简明解释

因为是看书杏彩平台出租haozbbs.comQ1446595067 自学的python,开始后不久就遇到了这个引入的模块函数,且一直在IDLE上编辑了后运行,试图从结果发现它的用途,然而结果一直都是没结果,也在网上查了许多,但发现这个问题的比较详细的解释只有一个版本,大部分都是转裁和复制的.给的都是简明python教程上那个一长串代码的例子,说看了就明白了,可我看得晕头转向的还是没真正明白,只知道"sys.argv[0]表示代码本身文件路径"这点,其实还是不明其意.后来经过大量努力,多

日本励志短片《人生各自精彩杏彩平台出租》

最近小朋友在游泳杏彩平台出租 下载地址 http://hxforum.com/thread-397-1-1.html QQ2952777280[话仙源码论坛]hxforum.com[木瓜源码论坛]papayabbs.com馆学游泳,给他报名的初衷是能够在炎热地环境中继续锻炼一下身体. 可是作为家长的我,在观看了几场游泳训练后,总觉得孩子不够认真和努力--, 接连的"没有追赶精神","没有认真听教练的话","旁边班的小朋友为什么都很熟练了",&qu

内核中ARP请求的回复控制与杏彩平台出租

ARP收到request请求之后,杏彩平台出租(企 娥:217 1793 408)首先通过路由查询确定目的IP为一个本地地址类型(RTN_LOCAL)后,是否回复arp请求,还取决于两个判断:arp_ignore与arp_filter.可通过sysctl或者proc文件系统查看二者的值,如下所有配置值都为0: $ sudo sysctl -a | grep -w arp_ignorenet.ipv4.conf.all.arp_ignore = 0net.ipv4.conf.default.arp

linux文本处理杏彩平台出租工具之grep与正则表达式语法

Grep介绍Linux 文本处理三剑客之一,文件过滤工具(另外两剑客为sed:文本编辑工具,awk:文本报告生成器) 拥有着,根据用户指定的"模式"对目标文本逐行进行匹配检查:打印匹配到的行的功能. 使用Grep除了正常的字符使用之外 还可以运用正则表达式字符. Grep的重要命令选项 --color=auto 关键字高亮显示(centos7默认) *-v 关键字 显示不包含关关键字的行,取反 *-i 关键字 忽略关键字的大小写 -n 显示的结果每行前增加行号 -c 仅显示找出的结果的

win10 windows许可证杏彩平台搭建即将过期的解决办法

出现这个错误是因为杏彩平台搭建安装论坛:haozbbs.com Q1446595067 的版本不是正版系统,每隔一段时间需要激活这次激活也费了一些时间,记录如下希望能对大家有所帮助 (1)首先可以查看自己的许可什么什么时候会过期windows+R调出命令运行窗口,输入slmgr.vbs -xpr这里写图片描述(2)用工具进行激活MicroKMS神龙版链接:https://pan.baidu.com/s/1bwrKMK_EfA-AnJKdPtaplA 密码:kv39这里写图片描述点击划线进行激活,

数据结构---在分内分彩平台出租存上理解链表

首先,在学习分内分彩平台出租haozbbs.comQ1446595067 数据结构中,对链表在内存上的理解非常重要,上代码public class LinkNode<M> {public M data;public LinkNode nextNode;br/>@Overridepublic String toString() {return "LinkNode [data=" + data + ", nextNode=" + nextNode +

C++STL库常腾讯分用分彩平台出租数据结构用法整理

vector腾讯分用分彩平台出租haozbbs.comQ1446595067创建对象,vector<int> vec;尾部插入数字,vec.push_back(a):使用下表访问元素使用迭代器访问元素插入元素删除最后一个元素,vec.pop_back() queue定义一个queue的变量 queue<Type> M查看是否为空范例 M.empty()从已有元素后面增加元素 M.push()输出现有元素的个数 M.size()显示第一个元素 M.front()显示最后一个元素 M.

MyEclispe SSH五分-彩平台出租项目框架搭建

基于MyEclipse2014,首先五分-彩平台出租 Q1446595067注意SHH框架的搭建顺序,Struts2-Spring-Hibernate1.搭建Struts2框架1.1首先创建Web Project,创建的时候注意勾选,会自动生成web.xml,否则自己手动创建比较麻烦**这里写图片描述1.2搭建Struts2框架.搭建SSH框架的方式有两种,第一种是自己下载jar包,手动导入,创建并编写配置文件,第二种通过MyEclipse自动创建,我们这里使用第二种! 右键项目-MyEclis