最近在做项目的时候用到了定时任务,而且用到的地方比较多,如果用配置文件配置的话,感觉不太方便,调整任务的执行方式也十分麻烦,因此,我采用了动态添加的方式,将定时任务保存在数据库中,这样既可以方便定时任务的添加,有能够随时改变、关闭定时任务。
定时任务的主要实现逻辑是在初始化完spring之后初始化定时任务,添加、修改定时任务时,调用相应的方法去修改定时任务不多说,直接上核心代码:
核心类:QuartzJobFactory
package com.thinkgem.jeesite.modules.task.quartz;
import java.util.List;
import org.apache.log4j.Logger;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import com.thinkgem.jeesite.common.utils.SpringContextHolder;
import com.thinkgem.jeesite.modules.task.dao.ScheduleJobDao;
import com.thinkgem.jeesite.modules.task.entity.ScheduleJob;
import com.thinkgem.jeesite.modules.task.quartz.uils.QuartzUtils;
/**
* 定时任务运行工厂类
*
*/
public class QuartzJobFactory {// 实现的是无状态的Job
private static Logger logger = Logger.getLogger(QuartzJobFactory.class);
private static ScheduleJobDao scheduleJobDao = SpringContextHolder.getBean(ScheduleJobDao.class);
/**
* @Note : 初始化定时任务
*/
public static void arrageScheduleJob() {
try {
List<ScheduleJob> jobList = scheduleJobDao.findList(new ScheduleJob());
if (jobList.size() != 0) {
for (ScheduleJob job : jobList) {
// Keys are composed of both a name and group, and the name must be unique within the group
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
// 获取trigger
CronTrigger trigger = (CronTrigger) QuartzUtils.scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
createSheduler(QuartzUtils.scheduler, job);
} else {// Trigger已存在,那么更新相应的定时设置
updateScheduler(QuartzUtils.scheduler, job, triggerKey, trigger);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 更新相应的定时设置 根据job_status做相应的处理
*
* @param scheduler
* @param job
* @param triggerKey
* @param trigger
* @throws SchedulerException
*/
private static void updateScheduler(Scheduler scheduler, ScheduleJob job, TriggerKey triggerKey, CronTrigger trigger)
throws SchedulerException {
if (job.getJobStatus().equals("1")) {// 0禁用 1启用
if (!trigger.getCronExpression().equalsIgnoreCase(job.getCronExpression())) {
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
logger.info(job.getJobGroup() + "." + job.getJobName() + " 更新完毕,目前cron表达式为:" + job.getCronExpression()
+ " isSpringBean:" + job.getIsSpringBean() + " concurrent: " + job.getConcurrent());
}
} else if (job.getJobStatus().equals("0")) {
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(trigger.getJobKey());// 删除任务
logger.info(job.getJobGroup() + "." + job.getJobName() + "删除完毕");
}
}
/**
* 创建一个定时任务,并做安排
*
* @param scheduler
* @param job
* @throws SchedulerException
* @throws Exception
*/
public static void createSheduler(Scheduler scheduler, ScheduleJob job) throws Exception {
// 在工作状态可用时,即job_status = 1 ,开始创建
if (job.getJobStatus().equals("1")) {
// 新建一个基于Spring的管理Job类
MethodInvokingJobDetailFactoryBean methodInvJobDetailFB = new MethodInvokingJobDetailFactoryBean();
// 设置Job名称
methodInvJobDetailFB.setName(job.getJobName());
// 定义的任务类为Spring的定义的Bean则调用 getBean方法
if (job.getIsSpringBean().equals("1")) {// 是Spring中定义的Bean
methodInvJobDetailFB
.setTargetObject(SpringContextHolder.getBean(job.getTargetObject()));
} else {// 不是
methodInvJobDetailFB.setTargetObject(Class.forName(job.getClazz()).newInstance());
}
// 设置任务方法
methodInvJobDetailFB.setTargetMethod(job.getTargetMethod());
// 将管理Job类提交到计划管理类
methodInvJobDetailFB.afterPropertiesSet();
/** 并发设置 */
methodInvJobDetailFB.setConcurrent(job.getConcurrent().equals("1") ? true : false);
JobDetail jobDetail = methodInvJobDetailFB.getObject();// 动态
jobDetail.getJobDataMap().put("scheduleJob", job);
//jobName存入到队列 每隔一段时间就会扫描所以需要时检测
if(!QuartzUtils.jobNames.contains(job.getJobName())){
QuartzUtils.jobNames.add(job.getJobName());
}
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup())
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);// 注入到管理类
logger.info(job.getJobGroup() + "." + job.getJobName() + "创建完毕");
}
}
/**
* 更新相应的定时设置 根据job_status做相应的处理
*
* @param scheduler
* @param job
* @param triggerKey
* @param trigger
* @throws SchedulerException
*/
public static void updateScheduler(ScheduleJob job)
throws Exception {
Scheduler scheduler = QuartzUtils.scheduler;
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
// 获取trigger
CronTrigger trigger = (CronTrigger) QuartzUtils.scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
createSheduler(scheduler, job);
return;
}
if (job.getJobStatus().equals("1")) {// 0禁用 1启用
if (!trigger.getCronExpression().equalsIgnoreCase(job.getCronExpression())) {
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
logger.info(job.getJobGroup() + "." + job.getJobName() + " 更新完毕,目前cron表达式为:" + job.getCronExpression()
+ " isSpringBean:" + job.getIsSpringBean() + " concurrent: " + job.getConcurrent());
}
} else if (job.getJobStatus().equals("0")) {
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(trigger.getJobKey());// 删除任务
logger.info(job.getJobGroup() + "." + job.getJobName() + "删除完毕");
}
}
/**
* 删除定时任务
*
* @param scheduler
* @param job
* @param triggerKey
* @param trigger
* @throws SchedulerException
*/
public static void deleteScheduler(ScheduleJob job)
throws Exception {
Scheduler scheduler = QuartzUtils.scheduler;
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
// 获取trigger
CronTrigger trigger = (CronTrigger) QuartzUtils.scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
return;
}
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(trigger.getJobKey());// 删除任务
logger.info(job.getJobGroup() + "." + job.getJobName() + "删除完毕");
}
}
在spring的配置文件中加入bean
<!-- 加载完spring启动此方法 -->
<bean class="com.thinkgem.jeesite.modules.task.quartz.InstantiationTracingBeanPostProcessor"></bean>
<!-- 任务工厂,注入需注入scheduler -->
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" ></bean>
InstantiationTracingBeanPostProcessor,加载完spring调用的文件
package com.thinkgem.jeesite.modules.task.quartz;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import com.thinkgem.jeesite.modules.task.elastic.JobInit;
import com.thinkgem.jeesite.modules.task.entity.ScheduleJob;
import com.thinkgem.jeesite.modules.task.quartz.uils.QuartzUtils;
public class InstantiationTracingBeanPostProcessor implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (event.getApplicationContext().getParent() == null) {// root
// application
// context
// 没有parent,他就是老大.
// 需要执行的逻辑代码,当spring容器初始化完成后就会执行该方法。
QuartzJobFactory.arrageScheduleJob();
}
}
}
在做定时任务时,参考了一些文章: