quartz集群 定时任务 改成可配置
前面的博文中提到的quartz集群方式会有以下缺点:
1.假设配置了3个定时任务,job1,job2,job3,这时数据库里会有3条job相关的记录,如果下次上线要停掉一个定时任务job1,那即使定时任务配置文件 quartz.xml 中的trigger 去掉了,数据库还是会有该条记录,若代码没有去掉,那定时任务还是会执行。
------解决方法1:修改该trigger的触发时间,比如年改成2099,让它不触发,(SchedulerFactoryBean中配置了 <property name="overwriteExistingJobs" value="true" />),会覆盖数据库中的相关记录。
缺点:曲线救国策略,不够好。
------解决方法2:删除数据库中该job的相关记录。
缺点:要操作数据库,而且表中数据还有外键约束,操作起来麻烦,还可能不小心破坏了其他job信息。
解决方法3:
介绍一种用配置文件的方式,通过开关控制,达到更细粒度的控制。主要是通过Scheduler的相关方法:Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。Scheduler包含了很多方法,添加、执行一次、恢复全部、删掉任务暂停全部等方法,方便用户灵活使用。
1.创建定时任务的配置文件 quartz-config.properties
#定时任务配置文件
#key:
# CronTriggerFactoryBean配置的id
# switch:定时任务开关,ON:开启该定时任务; OFF:关闭该定时任务
# cron:该定时任务的执行时间间隔(cron表达式)
#定时任务(每隔15分钟执行)
intrBillTrigger.switch=OFF
intrBillTrigger.cron=0 0/15 * * * ?
2.applicationContext-quartz.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <bean id="intrBillJob"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.cmcc.open.task.utils.MyDetailQuartzJobBean"></property> //参考以前的那篇博文
<property name="Durability" value="true"/>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="billTimerIntrTask" />
<entry key="targetMethod" value="intrBillTimer" />
</map>
</property>
</bean>
<bean id="intrBillTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="intrBillJob"></property>
<!--<property name="cronExpression" value="0 0/15 * * * ?"></property>-->
<property name="cronExpression" value="${intrBillTrigger.cron}"></property>
</bean> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource" ref="dataSourceQuartz"></property>
<property name="jobFactory" ref="customJobFactory"></property>
<property name="applicationContextSchedulerContextKey" value="applicationContext"></property>
<property name="configLocation" value="classpath:quartz.properties" /> //参考以前那篇博文
<property name="overwriteExistingJobs" value="true" />
<property name="triggers">
<list>
<ref bean="intrBillTrigger"/>
</list>
</property>
</bean>
</beans>
3.QuartzScheduleConfigTask 定时任务控制类
package com.cmcc.open.task.service; import com.cmcc.open.framework.utils.EncryptPropertyPlaceholderConfigurer; import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component; import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set; /**
* QuartzScheduleConfigTask.
* 初始化定时任务配置
*/
@Component
public class QuartzScheduleConfigTask {
/** The Constant log. */
private static Logger logger = LoggerFactory.getLogger(QuartzScheduleConfigTask.class);
private static Properties properties; @Autowired
private SchedulerFactoryBean schedulerFactoryBean; /**
* 初始化定时任务配置
*/
public void initQuartzConfig() {
String triggerName = null;
//读取定时任务配置文件(包括开关、执行时间)
Properties properties = getProperty();
if (properties == null) {
logger.warn(".......cannot find quartz-config properties file");
} try {
//解析定时任务配置文件,进行修改
Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
Scheduler sched = schedulerFactoryBean.getScheduler();
//先对读取到的配置进行过滤,将开关和cron放到同一个key中
Iterator it1 = entrySet.iterator();
while (it1.hasNext()) {
Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>)
it1.next();
String key = String.valueOf(entry.getKey());
if (!key.endsWith("switch")) {
continue;
}
triggerName = key.substring(0, key.lastIndexOf("."));
if ("OFF".equalsIgnoreCase(String.valueOf(entry.getValue()))) {
//关闭该定时任务
closeQuartz(sched, triggerName);
} else {
//获取该定时任务的执行时间,与配置文件进行比较
//目前定时任务的实现时间从配置文件中读取,不需要再进行修改
String cron = null;
Iterator it2 = entrySet.iterator();
while (it2.hasNext()) {
Map.Entry<Object, Object> entryChild = (Map.Entry<Object, Object>) it2.next();
if(!String.valueOf(entryChild.getKey()).startsWith(triggerName)
|| !String.valueOf(entryChild.getKey()).endsWith("cron")) {
continue;
}
cron = String.valueOf(entryChild.getValue());
it1.remove();
break;
}
updateQuartz(sched, triggerName, cron);
}
}
} catch (Exception e) {
logger.warn("Exception in trigger:" + triggerName);
logger.warn("Exception in initQuartzConfig:" + e.getMessage(), e);
} } /**
* 删除定时任务
* @param sched
* @param triggerName
* @throws Exception
*/
private void closeQuartz(Scheduler sched, String triggerName) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, Scheduler.DEFAULT_GROUP);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
logger.warn("no trigger get for key:" + triggerName + " do nothing for this trigger");
return;
} //如果定时任务关闭,则从数据库中移除
//停止触发器
sched.pauseTrigger(triggerKey);
//移除触发器
sched.unscheduleJob(triggerKey);
//删除任务
String jobName = trigger.getJobKey().getName();
sched.deleteJob(JobKey.jobKey(jobName, Scheduler.DEFAULT_GROUP));
logger.info("delete quartz job:" + jobName + " succ.........");
} /**
* 更新定时任务执行时间
* @param sched
* @param triggerName
* @param cron
* @throws Exception
*/
private void updateQuartz(Scheduler sched, String triggerName, String cron) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, Scheduler.DEFAULT_GROUP);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey); //如果定时任务开启,从数据库读取该job的执行时间进行比较
//如果相关不做任何处理,如果不等则更新数据库中的执行时间
String oldTime = trigger.getCronExpression();
if (!oldTime.equals(cron)) {
logger.info("quartz job's oldTime not equals config cron, trigger name is : " + triggerName
+ "|oldTime is : " + oldTime
+ "|config cron is : " + cron);
//触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
//触发其名,触发器组
triggerBuilder.withIdentity(triggerName, Scheduler.DEFAULT_GROUP);
triggerBuilder.startNow();
//触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
//创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
//修改一个任务的触发时间
sched.rescheduleJob(triggerKey, trigger);
logger.info("update quartz job:" + trigger.getJobKey().getName() + " succ.........");
} else {
logger.info("the quartz job's config cron is equals old cron, do nothing for this quartz: " + triggerName);
}
} /**
* 读取配置文件
* @return
*/
private Properties getProperty() {
try { // 先获取jvm传参
String pathRoot = "D:\\Test\\";
String path = pathRoot + "quartz-config.properties";
if ("".equals(pathRoot)){
path = QuartzScheduleConfigTask.class.getClassLoader().getResource("quartz-config.properties").getPath();
}
Resource resource = new FileSystemResource(path);
properties = PropertiesLoaderUtils.loadProperties(resource);
Set<Map.Entry<Object, Object>> entrySet = properties.entrySet();
for (Map.Entry<Object, Object> entry : entrySet) {
String decryptValue = EncryptPropertyPlaceholderConfigurer
.getDecryptPara(entry.getKey().toString(), entry.getValue().toString());
properties.setProperty(entry.getKey().toString(), decryptValue);
} return properties;
} catch (Exception e) {
logger.error(e.getMessage(), e);
} return null;
}
}
quartz集群 定时任务 改成可配置的更多相关文章
- 原!总结 quartz集群 定时任务 测试运行ok
由于项目优化重构,想将定时任务从quartz单机模式变成集群或分布式的方式.于是,百度了一圈....修修改改...用集群的方式部署定时任务,测试可以... 集群?分布式?什么区别? 集群:同一个业务, ...
- (4) Spring中定时任务Quartz集群配置学习
原 来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运 行,没有任何错误日志,于是从jar包.JDK版本. ...
- spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】
最近做了一个spring boot 整合 quartz 实现 动态定时任务配置,在集群环境下运行的 任务.能够对定时任务,动态的进行增删改查,界面效果图如下: 1. 在项目中引入jar 2. 将需要 ...
- Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群
Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群 >>>>>>>>>>>>>> ...
- Quartz集群配置
先看看quartz的持久化基本介绍: 引用 1 大家都清楚quartz最基本的概念就是job,在job内调用具体service完成具体功能,quartz需要把每个job存储起来,方便调度,quartz ...
- Quartz集群原理及配置应用
1.Quartz任务调度的基本实现原理 Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于Java实现.作为一个优秀的开源调度框架,Quartz具有以下特点: (1) ...
- 【原理、应用】Quartz集群原理及配置应用
一.Quartz任务调度的基本实现原理 Quartz是OpenSymphony开源组织在任务调度领域的一个开源项目,完全基于Java实现.作为一个优秀的开源调度框架,Quartz具有以下特点: 强大的 ...
- Spring集成quartz集群配置总结
1.spring-quartz.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE be ...
- quartz集群报错but has failed to stop it. This is very likely to create a memory leak.
quartz集群报错but has failed to stop it. This is very likely to create a memory leak. 在一台配置1核2G内存的阿里云服务器 ...
随机推荐
- Atitit。 沉思录 与it软件开发管理中的总结 读后感
Atitit. 沉思录 与it软件开发管理中的总结 读后感 1. <沉思录>,古罗马唯一一位哲学家皇帝马可·奥勒留所著 2 2. 沉思录与it软件开发管理中的总结 2 2.1. 要有自己的 ...
- [docker]一些经常或不经常用到的镜像启动方法-一些常用的docker启动方式
一些经常或不经常用到的镜像启动方法 设置容器的TZ另一种办法 参考: https://github.com/spujadas/elk-docker/blob/master/start.sh ## ov ...
- redis命令_INCR
INCR key 将 key 中储存的数字值增一. 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作. 如果值包含错误的类型,或字符串类型的值不能表示为数字,那 ...
- iOS直播-基于RTMP的视频推送
iOS直播-基于RTMP的视频推送 所谓的视频推送就是把摄像头和麦克风捕获到视频和音频推送到直播服务器上.我们这里使用推送协议是RTMP协议. 扩展:腾讯直播平台,阿里直播平台,百度直播平台提供均为R ...
- Compiler Error C2872: ambiguous symbol
参考资料:http://blog.csdn.net/greytree/article/details/354530 刚才写的程序报错ERROR C2872(CL.exe)原因很简单 ZThread有定 ...
- TCP/IP详解读书笔记:ARP-地址解析协议
地址解析为两种不同的地址形式提供映射:32bit的IP和数据链路层使用的任何类型的地址. 当一台主机把以太网数据帧发送到位于同一局域网的另一台主机,是根据48bit的以太网地址而不是IP地址.设备驱动 ...
- City Destruction Kattis - city dp
/** 题目:City Destruction Kattis - city 链接:https://vjudge.net/problem/Kattis-city 题意:有n个怪兽,排成一行.每个怪兽有一 ...
- 01 Java图形化界面设计——容器(JFrame)
程序是为了方便用户使用的,因此实现图形化界面的程序编写是所有编程语言发展的必然趋势,在命令提示符下运行的程序可以让我们了解java程序的基本知识体系结构,现在就进入java图形化界面编程. 一.Jav ...
- 尽管以C++为基础,但 Java 是一种更纯粹的面向对象程序设计语言
“尽管以C++为基础,但 Java 是一种更纯粹的面向对象程序设计语言”. 无论C++还是Java 都属于杂合语言.但在 Java 中,设计者觉得这种杂合并不象在 C++里那么重要.杂合语言 允许采用 ...
- 【转】SetThreadLocale解决越南文乱码问题
转自http://hi.baidu.com/killwolf110/item/838d56224067c63395f62b70 程序需要运行在越南地区,语言为越南文,操作系统为英文版,程序支持unic ...