随着需求的增加,现在要定时启动一个调度和计划任务,原先写的QuartzPlugin,是持久化保存到数据库中的,从数据库中读取任务并执行。要是添加一个每天循环任务,就要在代码里写一次开始任务的代码,执行后,再注释掉,最后重启项目。否则会因为启动同name,同group的任务而报错
org.quartz.ObjectAlreadyExistsException: Unable to store Job :
'group_test_1.job_test_1', because one already exists with this identification.
原先JFinal-ext中是通过配置文件,定时循环运行的,两者结合不就是我要的吗?
思路清晰,持久化依旧,再在QuartzPlugin 中增加读取配置文件后生成调度任务,当然,这个也会保存到数据库中的,所以还要在停止的时候,终止和删除相应调度任务,否则下次启动就会报冲突了。
修改的QuartzPlugin 依旧参考了jfinal-ext,做了一些修改,原先会依赖com.google.guava:guava这个jar,因为本人有点强迫症,不喜欢jar包太多,所以能不加就不加了。
import com.jfinal.plugin.IPlugin;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import sedion.net.gppz.quartz.QuartzFactory;
import sedion.net.gppz.utils.PropertiesUtil;
import java.util.*;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
/**
* Quartz插件
*
* @author WWF
*/
public class QuartzPlugin implements IPlugin {
private static final String JOB = "job";
/**
* 默认配置文件
**/
private String config = "quartz.properties";
private String job_config = "jobs.properties";
private Map<Job, String> jobs = new LinkedHashMap<>();
private Map<String, String> jobProp;
public QuartzPlugin() {
}
public QuartzPlugin(String config) {
this.config = config;
}
public QuartzPlugin(String config, String job_config) {
this.config = config;
this.job_config = job_config;
}
@Override
public boolean start() {
try {
//加载配置文件
Properties props = PropertiesUtil.loadPropertyFile(config);
//实例化
QuartzFactory.sf = new StdSchedulerFactory(props);
//获取Scheduler
Scheduler sched = QuartzFactory.sf.getScheduler();
//从配置文件中加载定时任务
loadJobsFromProperties();
if (jobs.size() > 0) {
Set<Map.Entry<Job, String>> set = jobs.entrySet();
for (Map.Entry<Job, String> entry : set) {
Job job = entry.getKey();
String jobClassName = job.getClass().getName();
String jobCronExp = entry.getValue();
JobDetail jobDetail = newJob(job.getClass())
.withIdentity(jobClassName, jobClassName)
.requestRecovery()
.build();
CronTrigger trigger = newTrigger()
.withIdentity(jobClassName, jobClassName)
.withSchedule(CronScheduleBuilder.cronSchedule(jobCronExp))
.build();
sched.scheduleJob(jobDetail, trigger);
}
}
sched.start();
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
public boolean stop() {
try {
//从配置文件中加载定时任务
loadJobsFromProperties();
Scheduler sched = QuartzFactory.sf.getScheduler();
if (jobs.size() > 0) {
Set<Map.Entry<Job, String>> set = jobs.entrySet();
for (Map.Entry<Job, String> entry : set) {
Job job = entry.getKey();
String jobClassName = job.getClass().getName();
TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobClassName);
Trigger trigger = sched.getTrigger(triggerKey);
if (trigger != null) {
sched.pauseTrigger(triggerKey);// 停止触发器
sched.unscheduleJob(triggerKey);// 移除触发器
sched.deleteJob(trigger.getJobKey());// 删除任务
}
}
}
sched.shutdown();
QuartzFactory.sf = null;
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 从配置文件中加载定时任务
*/
private void loadJobsFromProperties() {
//清空任务
jobs.clear();
Properties properties = PropertiesUtil.loadPropertyFile(job_config);
jobProp = new HashMap<>((Map) properties);
Set<Map.Entry<String, String>> entries = jobProp.entrySet();
for (Map.Entry<String, String> entry : entries) {
String key = entry.getKey();
if (!key.endsWith(JOB) || !isEnableJob(key)) {
continue;
}
String jobClassName = jobProp.get(key) + "";
String jobCronExp = jobProp.get(cronKey(key)) + "";
try {
Class c = Class.forName(jobClassName);
jobs.put((Job) c.newInstance(), jobCronExp);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 获得cron表达式
* @param key
* @return
*/
private String cronKey(String key) {
return key.substring(0, key.lastIndexOf(".") + 1) + "cron";
}
/**
* 是否开启
* @param key
* @return
*/
private boolean isEnableJob(String key) {
String enableKey = key.substring(0, key.indexOf(".") + 1) + "enable";
Object enable = jobProp.get(enableKey);
if (enable != null && "true".equalsIgnoreCase((enable + "").trim())) {
return true;
}
return false;
}
}
在看jfinal-ext源码的时候,有个疑问,
看介绍,job的配置文件是
#JobA
a.job=test.com.jfinal.plugin.quzrtz.JobA
a.cron=*/5 * * * * ?
a.enable=true
但是在代码中,转化为map后,获取相应的key的处理是
private String enable(String key) {
return key.substring(0, key.lastIndexOf(JOB)) + "enable";
}
private String cronKey(String key) {
return key.substring(0, key.lastIndexOf(JOB)) + "cron";
}
所以我觉得配置文件应该是
#JobA
a.job=test.com.jfinal.plugin.quzrtz.JobA
a.job.cron=*/5 * * * * ?
a.job.enable=true
或者是获得key的截取改一下
再次感谢jfinal 和jfinal-ext。