前言:本文主要提供quartz简单配置的解决方案。
附上quartzWithtool2.2.1.jar和本人增加的org.quartz.tool包里面的源码下载。
quartzWithtool2.2.1.jar:csdn下载
org.quartz.tool包:csdn下载
开发背景:在使用nutz框架的时候,需要用到quartz来开启定时任务的时候,不能像spring那样使用xml配置一系列的定时任务。需要自己编写代码去实现定时任务的添加,不利于代码维护。
使用方法:
1.添加quartzWithtool2.2.1.jar
2.nutz的ioc.js里面添加如下配置信息
quartz : {
type : "org.quartz.tool.QuartzBean",
fields : {
list : [
{
type : "org.quartz.tool.QuartzBean",
fields : {
name : "clientdie",
clazz : "com.chat.quartz.job.ClientDieJob",
trigger : "0 */1 * * * ?"//每到整数分钟就执行ClientDieJob
}
},
{
type : "org.quartz.tool.QuartzBean",
fields : {
name : "faqtip",
clazz : "com.chat.quartz.job.FaqTipJob",
trigger : "0 0 */1 * * ?",//每到整数小时就执行ClientDieJob和FaqTipJob
simpleDelay : "0s"//启动项目之后立即执行1次FaqTipJob
,jobDatas:[{
type : "org.quartz.tool.JobData",
fields : {
key : "mykey",
value : "myvalue"
}
},{
type : "org.quartz.tool.JobData",
fields : {
key : "mybool",
value : "false"
}
}]
}
} ]
}
}
3.在项目启动的时候调用
QuartzTool.loadSchedule(Mvcs.getIoc().get(QuartzBean.class, "quartz") );
注:也可以不使用js配置的方式注入 QuartzBean,可以自行在代码中动态生成
QuartzBean,然后调用loadSchedule。
关于QuartzBean的配置说明:
//-------------------------单个定时任务对应两个触发器(一个simple一个cron规则)-------------------------------------
{
type : "com.chat.quartz.QuartzBean",
fields : {
name : "clientdie",
clazz : "com.chat.quartz.job.ClientDieJob",
trigger : "0 */1 * * * ?",//每到整数分钟就执行ClientDieJob
simpleDelay : "7s", //启动项目之后7秒开始每间隔1秒执行ClientDieJob,一共执行10次
simpleRepeat : "10",
simpleRepeatDelay : "1s"
}
}
//-------------------------多个定时任务对应两个触发器(一个simple一个cron规则)-------------------------------------
{
type : "com.chat.quartz.QuartzBean",
fields : {
name : "faqtip",
clazz : "com.chat.quartz.job.ClientDieJob,com.chat.quartz.job.FaqTipJob",
trigger : "0 0 */1 * * ?",//每到整数小时就执行ClientDieJob和FaqTipJob
simpleDelay : "0s",//启动项目之后立即每间隔2秒执行ClientDieJob和FaqTipJob,一共执行3次
simpleRepeat : "3",
simpleRepeatDelay : "2s"
}
}
//-------------------------一个定时任务对应一个simple------------------------------------
{
type : "com.chat.quartz.QuartzBean",
fields : {
name : "faqtipsimple5",
clazz : "com.chat.quartz.job.FaqTipJob",
simpleDelay : "0s",//启动项目之后立即每间隔5秒执行FaqTipJob,不限执行次数
simpleRepeat : "-1",
simpleRepeatDelay : "5s"
}
}
//-----------------------------------如果需要给定时任务传递数据请配置jobDatas属性-------------------------------------------
jobDatas:[{
type : "com.chat.quartz.JobData",
fields : {
key : "mykey",
value : "myvalue"
}
},{
type : "com.chat.quartz.JobData",
fields : {
key : "mybool",
value : "false"
}
}]
//设置了jobdata之后,在具体的job里面 像下面那样使用使用
System.out.println( arg0.getJobDetail().getJobDataMap().get("mykey") );
System.out.println( arg0.getJobDetail().getJobDataMap().getBooleanValue("mybool") );
org.quartz.tool包的源码:
package com.chat.quartz; import java.util.Date; import java.util.HashMap; import java.util.HashSet; 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.JobDataMap; import org.quartz.JobDetail; import org.quartz.ScheduleBuilder; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.SimpleScheduleBuilder; import org.quartz.SimpleTrigger; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.quartz.impl.StdSchedulerFactory; import org.quartz.spi.MutableTrigger; /** * 定时任务工具类 * * @author hp * */ public class QuartzTool { /** * quartz的Scheduler工厂类 */ private static SchedulerFactory sf = null; /** * 定时器map,主要是停止定时器的时候使用 */ private static Map <String, Scheduler> schedMap= new HashMap<String, Scheduler>(); /** * 定时器配置对象 */ private static QuartzBean quartzBean = null; /** * 启动定时器 * @param key 定时器名称 */ private static void startSchedule(String key){ for (QuartzBean bean : getQuartzBean().getList()) { if(bean.getName().equals( key )){ startSchedule(bean); break; } } } /** * 重新启动定时器 * @param key 定时器名称 */ public void reStartSchedule(String key){ for (QuartzBean bean : getQuartzBean().getList()) { if(bean.getName().equals( key )){ shutdownSchedule(key); startSchedule(bean); break; } } } /** * 获取定时器配置对象 * @return */ public static QuartzBean getQuartzBean() { return quartzBean; } /** * 启动定时器 * @param bean 定时bean的 */ public static void startSchedule(QuartzBean bean){ try { //map使用bean的name作为key String key = bean.getName(); if( schedMap.containsKey(key) ){//如果已经启动了该定时器,先停止再启动 shutdownSchedule(key); } Scheduler sched = getSf().getScheduler(); //根据配置生成job集合 Set<JobDetail> jobSet = makeJobSet( bean ); if(jobSet.size() <= 0){ System.out.println("初始化SCheduler失败:" + bean.getName()+"没有配置job的clazz属性。"); return ; } //根据配置bean生成trigger集合 Set<Trigger> tSet = makeTriggerSet( bean ); if(tSet.size() <= 0){ System.out.println("初始化SCheduler失败:" + bean.getName()+"没有配置任何trigger。"); return ; } //根据job集合和触发器集合生成schedule需要的map参数 Map map = makeSchedMap(jobSet, tSet); sched.scheduleJobs(map, true); //sched.scheduleJob( job, tSet , true); sched.start(); schedMap.put(key, sched); } catch (SchedulerException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 根据job集合和触发器集合生成schedule需要的map参数 * @param jobSet * @param tSet * @return */ private static Map makeSchedMap(Set<JobDetail> jobSet, Set<Trigger> tSet) { Map map = new HashMap(); int i = 0;//job循环变量 for (JobDetail job : jobSet) { Set<Trigger> cloneTriggerSet = new HashSet<Trigger>(); //根据每个任务动态生成对应的jobkey for (Trigger trigger : tSet) { MutableTrigger mTrigger = (MutableTrigger) trigger; if(mTrigger != null){ MutableTrigger cloneTrigger = (MutableTrigger) mTrigger.clone(); cloneTrigger.setJobKey(job.getKey()); //因为triggerkey不能重复,所以这里重新设置trigger的key为原来的值加上jobkey的值 cloneTrigger.setKey(cloneTrigger.getKey().triggerKey( cloneTrigger.getKey().getName() + cloneTrigger.getJobKey() )); //为了让trigger同时触发的时候有个优先顺序,这里设置一下优先级,job越靠前的 优先级越高 cloneTrigger.setPriority(Trigger.DEFAULT_PRIORITY + 90 - i); cloneTriggerSet.add(cloneTrigger); } } map.put(job, cloneTriggerSet); i ++; } return map; } /** * 根据配置生成job集合 * @param bean * @return * @throws ClassNotFoundException */ private static Set<JobDetail> makeJobSet(QuartzBean bean) throws ClassNotFoundException { Set<JobDetail> jobSet = new HashSet<JobDetail>(); //clazz没有直接返回 if(StringIsEmpty(bean.getClazz()) ){ return jobSet; } //构建jobDataMap JobDataMap jobDataMap = makeJobDataMap(bean); String[] clazzArr = bean.getClazz().split(","); for (int i = 0; i < clazzArr.length; i++) { String clazz = clazzArr[i]; JobDetail job = JobBuilder.newJob((Class<? extends Job>) Class.forName(clazz )) .usingJobData(jobDataMap) .withIdentity(bean.getName() + i ) .build(); jobSet.add(job); } return jobSet; } /** * 根据bean里面的JobDatas生成quartz里面的jobDataMap * @param bean * @return */ private static JobDataMap makeJobDataMap(QuartzBean bean) { JobDataMap jobDataMap = new JobDataMap(); for (JobData jobData : bean.getJobDatas()) { jobDataMap.put(jobData.getKey(), jobData.getValue()); } return jobDataMap; } /** * 生成调度规则集合,暂时只支持一个cron和一个simple * @param bean 调度规则配置对象 * @return */ private static Set<Trigger> makeTriggerSet(QuartzBean bean) { Set<Trigger> tSet = new HashSet<Trigger>(); CronTrigger cTrigger = makeCTrigger( bean ); SimpleTrigger sTrigger = makeSTrigger( bean ); if( cTrigger!=null ) tSet.add(cTrigger); if( sTrigger!=null ) tSet.add(sTrigger); return tSet; } /** * 生成简单的trigger * @param bean * @return */ private static SimpleTrigger makeSTrigger(QuartzBean bean) { //根据delay生成相对当前时间的一个时间,只支持加时间。 Date beginDate = makeDate( bean.getSimpleDelay() ); if( beginDate == null ) return null; //简单调度规则的开始时间 TriggerBuilder tBulder = TriggerBuilder.newTrigger() .withIdentity( "sTrigger", bean.getName() ) .startAt(beginDate ); //生成简单调度规则的重复次数 ScheduleBuilder sBulder = makeSimpleTriggerRepeat(bean); if(sBulder != null) tBulder.withSchedule(sBulder); SimpleTrigger sTrigger = (SimpleTrigger) tBulder.build(); return sTrigger; } /** * 根据规则生成trigger * @param bean 调度任务配置对象 * @return */ private static CronTrigger makeCTrigger(QuartzBean bean) { //调度规则 String role = bean.getTrigger(); if( StringIsEmpty(role) ){ return null; } CronScheduleBuilder schedule = CronScheduleBuilder.cronSchedule(role); CronTrigger trigger = TriggerBuilder.newTrigger().withSchedule(schedule) .withIdentity( "cTrigger", bean.getName() ).build(); return trigger; } /** * 生成简单调度规则的重复次数 * @param bean * @return */ private static ScheduleBuilder makeSimpleTriggerRepeat(QuartzBean bean) { ScheduleBuilder sBulder = null; //重复次数 Integer count = bean.getSimpleRepeat(); //不重复直接返回null,重复次数为0 或者没有重复的间隔时间即为不重复 if( count == 0 || StringIsEmpty(bean.getSimpleRepeatDelay() ) ){ return null; } //根据delay字符串生成时间对象 IntervalObject io = makeIntervalObj(bean.getSimpleRepeatDelay()); if(io == null){ return null; } if(count == -1)//-1次表示一直循环 sBulder = SimpleScheduleBuilder.repeatSecondlyForever(io.getSecond()); else sBulder = SimpleScheduleBuilder.repeatSecondlyForTotalCount(count, io.getSecond() ); return sBulder; } /** * 根据delay生成相对当前时间的一个时间,只支持加时间。 * @param delay 相对时间字符串,比如20s(20秒) 3m(3分钟) 60D(60天) * @return */ private static Date makeDate(String delay) { if( StringIsEmpty(delay ) ){ return null; } //根据delay字符串生成时间对象 IntervalObject io = makeIntervalObj(delay); if(io == null){ return null; } Date date = DateBuilder.futureDate(io.getInterval(), io.getUnit()); return date; } /** * 根据delay字符串生成时间对象 * @param delay * @return */ private static IntervalObject makeIntervalObj(String delay) { String[] numArr = delay.split("[^\\d]"); Integer interval = Integer.valueOf( StringsJoin("", numArr) ); if(interval == null || interval < 0){ return null; } //不带单位的时候,默认使用毫秒作单位 IntervalUnit unit = IntervalUnit.MILLISECOND; if( delay.endsWith("ms") ){ unit = IntervalUnit.MILLISECOND; }else if( delay.endsWith("s") ){ unit = IntervalUnit.SECOND; }else if( delay.endsWith("m") ){ unit = IntervalUnit.MINUTE; }else if( delay.endsWith("D") ){ unit = IntervalUnit.DAY; }else if( delay.endsWith("M") ){ unit = IntervalUnit.MONTH; }else if( delay.endsWith("Y") ){ unit = IntervalUnit.YEAR; } IntervalObject io = new IntervalObject(interval, unit); return io; } /** * 停止定时器 */ public static void shutdownSchedule(String key) { if( ! schedMap.containsKey(key)){ return; } Scheduler sched = schedMap.remove(key); if (null != sched) { try { sched.shutdown(); } catch (SchedulerException e) { e.printStackTrace(); } } } /** * 初始化系统定时器 */ public static void loadSchedule(QuartzBean baseBean){ quartzBean = baseBean; for (QuartzBean bean : baseBean.getList()) { startSchedule(bean); } } /** * 获取quartz的Scheduler工厂类 * @return */ public static SchedulerFactory getSf() { if(sf == null) sf = new StdSchedulerFactory(); return sf; } /** * 判断字符串是否为null或者空字符串 * @param clazz * @return */ private static boolean StringIsEmpty(String str) { if(str == null || str.trim() == ""){ return true; } return false; } /** * 字符串数组连接成一个字符串 * @param split 分割字符串 * @param numArr 字符串数组 * @return */ private static String StringsJoin(String split, String[] numArr) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < numArr.length; i++) { sb.append(numArr[i] ); if(i != numArr.length - 1 ) sb.append(split); } return sb.toString(); } }
/** * Quartz配置的bean * @author chencong * */ public class QuartzBean { /* * 定时任务名称 * 用于停止的时候使用 */ private String name; /** * 任务的class<br/> * 多个调度任务的情况下,使用,分割 */ private String clazz; /** * 定时任务的数据集合 */ private List<JobData> jobDatas = new ArrayList<JobData>(); /** * 调度规则 */ private String trigger; /** * 启动后多久执行一次,简单调度规则的开始时间<br/> * 格式使用数字加单位,纯数字的单位为ms(毫秒)<br/> * 单位:ms(毫秒) s(秒) m(分) h(小时) D(天) M(月) Y(年)<br/> * 比如20s(20秒) 3m(3分钟) 60D(60天) */ private String simpleDelay; /** * 简单调度规则的重复次数 0表示不重复 -1表示一直重复 <br/> * 默认为1 当指定了简单调度规则但是没指定重复次数默认执行1次 */ private Integer simpleRepeat = 1; /** * 简单调度规则的重复间隔时间<br/> * 格式使用数字加单位,纯数字的单位为ms(毫秒)<br/> * 单位:ms(毫秒) s(秒) m(分) h(小时) D(天) M(月) Y(年)<br/> * 比如20s(20秒) 3m(3分钟) 60D(60天) * 没有指定这个属性不会重复执行简单调度规则 */ private String simpleRepeatDelay; /** * Quartz配置集合 用于多 */ private List<QuartzBean> list = new ArrayList<QuartzBean>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public String getTrigger() { return trigger; } public void setTrigger(String trigger) { this.trigger = trigger; } public List<QuartzBean> getList() { return list; } public void setList(List<QuartzBean> list) { this.list = list; } public String getSimpleDelay() { return simpleDelay; } public void setInitDelay(String simpleDelay) { this.simpleDelay = simpleDelay; } public Integer getSimpleRepeat() { return simpleRepeat; } public void setSimpleRepeat(Integer simpleRepeat) { this.simpleRepeat = simpleRepeat; } public String getSimpleRepeatDelay() { return simpleRepeatDelay; } public void setSimpleRepeatDelay(String simpleRepeatDelay) { this.simpleRepeatDelay = simpleRepeatDelay; } public List<JobData> getJobDatas() { return jobDatas; } public void setJobDatas(List<JobData> jobDatas) { this.jobDatas = jobDatas; } }
package com.chat.quartz; /** * 定时任务的数据 * @author lenovo * */ public class JobData{ private String key; private Object value; public String getKey() { return key; } public void setKey(String key) { this.key = key; } public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } }
package com.chat.quartz; import org.quartz.DateBuilder.IntervalUnit; /** * 时间对象,内部类,包含时间数字和时间单位 * @author lenovo * */ public class IntervalObject { /** * 时间的数字 */ private Integer interval; /** * 时间的单位 */ private IntervalUnit unit; /** * 获取时间的数字 * @return */ public Integer getInterval() { return interval; } /** * 设置时间的数字 * @param interval */ public void setInterval(Integer interval) { this.interval = interval; } /** * 获取时间的单位 * @return */ public IntervalUnit getUnit() { return unit; } /** * 设置时间的单位 * @param unit */ public void setUnit(IntervalUnit unit) { this.unit = unit; } /** * 获取时间的秒数 * @return */ public Integer getSecond(){ if(this.getUnit() == null){ return null; } Integer Second = null; switch (getUnit()) { case MILLISECOND: Second = (int) Math.ceil(this.getInterval() / 1000.0 ); break; case SECOND: Second = this.getInterval(); break; case MINUTE: Second = this.getInterval() * 60; break; case HOUR: Second = this.getInterval() * 60 * 60; break; case DAY: Second = this.getInterval() * 60 * 60 * 24; break; case MONTH: //这里有问题 月按照30天一个月来计算 Second = this.getInterval() * 60 * 60 * 24 * 30; break; case YEAR: //这里有问题 年按照365天来算 Second = this.getInterval() * 60 * 60 * 24 * 365; break; default: break; } return Second; } public IntervalObject(Integer interval, IntervalUnit unit) { super(); this.interval = interval; this.unit = unit; } public IntervalObject() { super(); } }