quartz的例子已经分享过了,然而。需求总是会在你以为准备好的时候发生变化。
项目要求变更为:不仅仅要使用quartz定时器在配置文件配置,还要支持数据库动态配置,并且不能通过重启生效(在线生效)。
当时就是晴天霹雳,我也就是对spring定时任务入门而已。都不知道能不能实现这个功能。好在天无绝人之路,我在博客上面发现了可以实现该功能的样例。
博客地址:Spring整合Quartz实现动态定时
于是参考这位大神的代码,自己麻溜的配置了一番。效果实现了!跟那博主的是一样的。开心死~~~
以为搞定了。一般连续剧播放到这里,灾难就要开始了。
真的整合到项目的时候发现一个可怕的事情,用定时器跑代码的时候,无法解决bean注入的问题。都是null
于是老夫就用了一个比较low的办法去补这个漏洞,手工获取bean,只有bean为null,我就赋值给哪个bean对象。效果看起来杠杠的,貌似没啥缺点!后面网上找资料发现,这个办法有个弊端,就是会增加服务的开销。
老夫只能含着泪水整改那些代码了。
好在找到另外一位大神的博客:Quartz的使用(解决quartz的job无法注入spring对象)
根据这位博主的做,麻溜的跑了三回,期间因为jar包,环境等等其他问题。终于跑出来该博主的结果!
喜出望外,悲剧又㕛叒叕发生了。动态更改定时任务的方法失败了(有bug)。那可是我整合这个定时器的核心人物呀。
双腿都跪下了,于是自己补全了两个修改的方法。终于实现了我的目的!下面就是我项目中的代码。
会跟上面两位大神的步骤重复,所以只要是重合的部分直接引用他们的。
package com.sap.test.timerTest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class QuartzManager {
@Autowired
private Scheduler sched;
/**
* @Description 增加一个job
* @param jobClass 任务实现类
* @param jobName 任务名称
* @param jobGroupName 任务组名
* @param jobTime 时间表达式 (如:0/5 * * * * ? )
*/
public void addJob(Class extends Job> jobClass, String jobName,String jobGroupName,String jobTime) {
try {
//创建jobDetail实例,绑定Job实现类
//指明job的名称,所在组的名称,以及绑定job类
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroupName)//任务名称和组构成任务key
.build();
//定义调度触发规则
//使用cornTrigger规则
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(jobName, jobGroupName)//触发器key
.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime))
.startNow().build();
//把作业和触发器注册到任务调度中
sched.scheduleJob(jobDetail, trigger);
// 启动
if (!sched.isShutdown()) {
sched.start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 增加一个job
* @param jobClass 任务实现类
* @param jobName 任务名称
* @param jobGroupName 任务组名
* @param jobTime 时间表达式 (这是每隔多少秒为一次任务)
*/
public void addJob(Class extends Job> jobClass, String jobName,String jobGroupName,int jobTime){
addJob(jobClass,jobName,jobGroupName,jobTime,-1);
}
/**
* @Description 增加一个job
* @param jobClass 任务实现类
* @param jobName 任务名称
* @param jobGroupName 任务组名
* @param jobTime 时间表达式 (这是每隔多少秒为一次任务)
* @param jobTimes 运行的次数 (<0:表示不限次数)
*/
public void addJob(Class extends Job> jobClass, String jobName,String jobGroupName,int jobTime,int jobTimes){
try {
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(jobName, jobGroupName)//任务名称和组构成任务key
.build();
//使用simpleTrigger规则
Trigger trigger=null;
if(jobTimes<0){
trigger=TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))
.startNow().build();
}else{
trigger=TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))
.startNow().build();
}
sched.scheduleJob(jobDetail, trigger);
if (!sched.isShutdown()) {
sched.start();
}
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description 修改 一个job的 时间表达式 测试发现这个定时器有问题。
* @param jobName
* @param jobGroupName
* @param jobTime
*/
public void updateJob1(String jobName,String jobGroupName,String jobTime){
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule(jobTime))
.build();
//重启触发器
sched.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description 修改一个任务的触发时间 方式一
* @param jobName
* @param jobGroupName
* @param jobTime 时间设置,参考quartz说明文档
*/
public void modifyJobTime(String jobName, String jobGroupName, String jobTime) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(jobTime)) {
// 触发器
TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(jobName, jobGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(jobTime));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
sched.rescheduleJob(triggerKey, trigger);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description 修改一个任务的触发时间 方式二
* @param jobName
* @param jobGroupName
* @param jobTime 时间设置,参考quartz说明文档
*/
public void updateJob(Class extends Job> jobClass,String jobName,String jobGroupName,String jobTime){
deleteJob(jobName,jobGroupName);
addJob(jobClass,jobName,jobGroupName,jobTime);
}
/**
* @Description 修改 一个job的 简单的定时任务
* @param jobName
* @param jobGroupName
* @param jobTime
*/
public void updateJob(Class extends Job> jobClass,String jobName,String jobGroupName,int jobTime){
deleteJob(jobName,jobGroupName) ;
addJob(jobClass,jobName,jobGroupName,jobTime,-1);
}
/**
* @Description 删除任务一个job
* @param jobName 任务名称
* @param jobGroupName 任务组名
*/
public void deleteJob(String jobName,String jobGroupName) {
try {
sched.deleteJob(new JobKey(jobName, jobGroupName));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* @Description 暂停一个job
* @param jobName
* @param jobGroupName
*/
public void pauseJob(String jobName,String jobGroupName){
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
sched.pauseJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description 恢复一个job
* @param jobName
* @param jobGroupName
*/
public void resumeJob(String jobName,String jobGroupName){
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
sched.resumeJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description 立即执行一个job
* @param jobName
* @param jobGroupName
*/
public void runAJobNow(String jobName,String jobGroupName){
try {
JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
sched.triggerJob(jobKey);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
/**
* @Description 获取所有计划中的任务列表
*/
public List
package com.yj.quartzjob;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yj.service.WeiXinService;
/**
* quart test
*
*/
@Component
public class QuartzJob implements Job{
@Autowired
public WeiXinService service;
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
System.out.println("TestQuartJob 的运行 :"+dateFormat.format(new Date()));
service.getAccessToken();
}
}
@RequestMapping("add")
public void text(){
try {
String jobName="job1";
String jobGroupName="job1";
String jobTime="0/5 * * * * ? ";
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
System.out.println("TestQuartJob 开始启动:"+dateFormat.format(new Date()));
quartzManager.addJob(QuartzJob.class,jobName,jobGroupName,jobTime);
} catch (Exception e) {
e.printStackTrace();
}
}
貌似Quartz的job在项目重启时,job都失效了,我是把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job。
package com.sap.test.timerTest;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.quartz.Job;
import org.springframework.web.context.support.WebApplicationContextUtils;
import com.sap.service.api.ISysServerApiSetService;
import com.sap.vo.SysServerApiSetVO;
import utils.TimeExpressionUtil;
/**
* 容器监听器
*/
@SuppressWarnings("unchecked")
public class QuartzJobListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent arg0) {
/**初始化定时器任务表的锁状态为0*/
ISysServerApiSetService sysServerApiSetService = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(ISysServerApiSetService.class);
SysServerApiSetVO VO = new SysServerApiSetVO();
VO.setLock_status("0");
List timeList = new ArrayList<>();
timeList.add(VO);
sysServerApiSetService.updateSysServerApiSet(timeList);
/***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);
/**查询数据库获取所有定时任务数据*/
List list = sysServerApiSetService.getSysServerApiSetVO();
for (SysServerApiSetVO sysServerApiSetVO : list) {
try {
String jobClass = sysServerApiSetVO.getClass_name();
String jobName = sysServerApiSetVO.getItem_code();
String jobGroupName = sysServerApiSetVO.getItem_name();
//判断是接口一还是接口二,判断用表达式定时器还是简单的毫秒定时器。
if(!TimeExpressionUtil.isNumeric(TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency()))) {
String jobTime = TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency());
quartzManager.addJob((Class extends Job>)(Class.forName(jobClass).newInstance().getClass()), jobName, jobGroupName, jobTime);
}else {
int jobTime = Integer.parseInt(TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency()));
quartzManager.addJob((Class extends Job>)(Class.forName(jobClass).newInstance().getClass()), jobName, jobGroupName, jobTime);
}
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
System.out.println("QuartzJobListener 启动了");
}
public void contextDestroyed(ServletContextEvent arg0) {
/***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);
/**查询数据库获取所有定时任务数据*/
ISysServerApiSetService sysServerApiSetService = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(ISysServerApiSetService.class);
List list = sysServerApiSetService.getSysServerApiSetVO();
for (SysServerApiSetVO sysServerApiSetVO : list) {
try {
String jobName = sysServerApiSetVO.getItem_code();
String jobGroupName = sysServerApiSetVO.getItem_name();
quartzManager.deleteJob(jobName, jobGroupName);
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println("QuartzJobListener 删除了");
}
}
这个配置就是项目启动的时候去数据库找到定时器的信息。调度定时任务用!当项目启动执行数据库钟状态为一的所有定时任务。项目关闭的时候关闭所有的定时任务。由于写得比较不友好,怕大家看不懂,建议看第二位大神的博客的最后一个步骤。
PS:不知道为什么不能缺少两个jar包:slf4j-log4j12-1.5.11.jar和slf4j-api-1.5.11.jar
下面的是我数据库的信息: