打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
基于quartz触发器管理及动态创建触发器

年前做了个触发器管理,将以前设计不合理的地方修改掉了。

所谓动态创建,就是触发器的时间、触发器的任务由用户自己去设定,当然这个任务还是需要开发人员手动去写。

以前同事做的触发器管理,将某个任务写死,没法做到扩展,也没有持久化方面的考虑

后来参考 http://sundoctor.iteye.com/blog/399980  中提到的持久化方法,进行修改,已经满足要求。


本文使用的是quartz的1.7版本,quartz好像是分为两部分,一部分是任务(job)一个是触发器(trigger);trigger运行过程中,达到触发时间条件,将会执行job。

触发器管理模块需要提供触发器动态创建、删除、暂停、恢复功能,并结合spring做到job的扩展

在与spring整合时,有两个配置项 jobDetails和triggers

  1. <bean id="schedulerFactory" lazy-init='false'  
  2.     class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
  3.           
  4.     <property name="dataSource" ref="dataSource" />  
  5.     <property name="applicationContextSchedulerContextKey"  
  6.         value="applicationContextKey" />  
  7.     <property name="configLocation"  
  8.         value="classpath:quartz.properties" />  
  9.     <property name="startupDelay" value="30" />  
  10.           
  11.     <!-- property name="overwriteExistingJobs" value="true" / -->  
  12.     <!-- 可用的job列表 -->  
  13.     <property name="jobDetails">  
  14.         <list>  
  15.             <!-- 示例 -->  
  16.             <ref bean="avicinfo.test.testJobService" />  
  17.         </list>  
  18.     </property>  
  19.   
  20.     <!-- 默认启动的trigger列表 -->  
  21.     <property name="triggers">  
  22.         <list>  
  23.             <ref bean="OnlineDocDeleteRubbishFilesJobTrigger" />  
  24.         </list>  
  25.     </property>  
  26. </bean>  

triggers中配置的信息已经是完整的触发器了,包含时间、job等信息,这部分会在SchedulerFactoryBean生成Scheduler对象时,就已经加载到触发器列表中了。

jobDetails是job的配置部分,想要做到由用户选择触发什么job,就要从这里入手。

通过quartz的api了解到,我使用的这个版本,没有直接提供获取所有job的方法,而是可以通过查找所有jobGroupName,得到最后的job对象,而在我的触发器管理模块中,默认启动的trigger是不能被删除的,所以将这些trigger中job的group不做设置,即默认组(DEFAULT),而其他在jobDetails中配置的job需要强制设定组信息,并且还要实现固定的接口,以达到对这些动态创建trigger的管理。

获取可以用于动态创建的job

  1. public List<JobDetail> getCanUseQrtzJobs() throws SchedulerException {  
  2.     List<JobDetail> list = new ArrayList<JobDetail>();  
  3.     String[] jobGroupNames = this.scheduler.getJobGroupNames();  
  4.     for (String jobGroupName : jobGroupNames) {  
  5.         // 去掉受保护的分组  
  6.         if (!CANNOT_USE_GROUPS.contains(jobGroupName)) {  
  7.             String[] jobNames = this.scheduler.getJobNames(jobGroupName);  
  8.             for (String jobName : jobNames) {  
  9.                 JobDetail jd = this.scheduler.getJobDetail(jobName, jobGroupName);  
  10.                 // 获取实际调度对象  
  11.                 Object targetObject = jd.getJobDataMap().get("targetObject");  
  12.                 if (StaticMethod.hasInterface(targetObject.getClass(), CAN_USE_INTERFACES)) {  
  13.                     try {  
  14.                         Object obj = PropertyUtils.getProperty(targetObject, "triggerName");  
  15.                         if (StaticMethod.isEmpty(obj)) {  
  16.                             list.add(jd);  
  17.                         }  
  18.                     } catch (IllegalAccessException e) {  
  19.                         e.printStackTrace();  
  20.                     } catch (InvocationTargetException e) {  
  21.                         e.printStackTrace();  
  22.                     } catch (NoSuchMethodException e) {  
  23.                         e.printStackTrace();  
  24.                     }  
  25.   
  26.                 }  
  27.             }  
  28.         }  
  29.     }  
  30.     return list;  
  31. }  
job需要实现的接口,提供管理连接,和唯一标识这个trigger的属性,我使用的是triggerName,全局唯一。

  1. /** 
  2.  * @author lisen 
  3.  * @date Jan 17, 2014 1:56:42 PM 
  4.  */  
  5. public interface SchedulerJobDetail extends Cloneable {  
  6.   
  7.     /** 
  8.      * 获得展现页面的地址 不包括ip 端口号 工程名 
  9.      *  
  10.      * @return 
  11.      */  
  12.     String getActionUrl();  
  13.   
  14.     /** 
  15.      * 显示名称 
  16.      *  
  17.      * @return 
  18.      */  
  19.     String getDisplayName();  
  20.   
  21.     /** 
  22.      * 设置触发器名 对象唯一识别 
  23.      *  
  24.      * @param triggerName 
  25.      */  
  26.     void setTriggerName(String triggerName);  
  27.   
  28.     /** 
  29.      * 获取触发器名 
  30.      *  
  31.      * @return 
  32.      */  
  33.     String getTriggerName();  
  34.   
  35. }  
在启动一个trigger时,可以根据选择的jobName,jobGroup,获取到这个job的配置对象,将它塞到创建的trigger对象中,但是在这个trigger执行完毕后,他的job也随之被释放了,持久化的对象被删除。而quartz提供的持久化方法,仅仅判断jobName和jobGroup,所以在创建时,要在获取配置中得到job的name做下手脚,让他变成一个唯一对象,这样,trigger的生命周期如何,都和我们配置job没有关系了

  1.     @Override  
  2.     public void schedule(String triggerName, String triggerGroup, String jobDetailName,  
  3.             String jobDetailGroup, String cronExpression, boolean overwriteExistingTrigger) {  
  4.         try {  
  5.             // 保证有这个job  
  6.             JobDetail tjd = this.scheduler.getJobDetail(jobDetailName, jobDetailGroup);  
  7.             if (!StaticMethod.isEmpty(tjd)) {  
  8.                 JobDetail jd = (JobDetail) tjd.clone();  
  9.                 // 处理获取到的job  
  10.                 handleJobDetail(jd, triggerName);  
  11.                 this.scheduler.addJob(jd, true);  
  12.                 Trigger t = this.scheduler.getTrigger(triggerName, triggerGroup);  
  13.                 if (!StaticMethod.isEmpty(t) && overwriteExistingTrigger) {  
  14.                     this.removeTrigger(triggerName, triggerGroup);  
  15.                 }  
  16.                 CronTrigger cronTrigger = new CronTrigger(triggerName, triggerGroup, jd.getName(),  
  17.                         jd.getGroup());  
  18.                 cronTrigger.setCronExpression(cronExpression);  
  19.                 this.scheduler.scheduleJob(cronTrigger);  
  20.             }  
  21.         } catch (Exception e) {  
  22.             throw new SchedulerRuntimeException(e);  
  23.         }  
  24.     }  
  25.   
  26.     protected void handleJobDetail(JobDetail jd, String triggerName) {  
  27.         jd.setDescription(jd.getName());  
  28.         jd.setName(UUID.randomUUID().toString());  
  29.         // 获取实际调度对象  
  30.         Object targetObject = jd.getJobDataMap().get("targetObject");  
  31.         if (StaticMethod.hasInterface(targetObject.getClass(), CAN_USE_INTERFACES)) {  
  32.             try {  
  33.                 Object cloneTargetObject = MethodUtils.invokeMethod(targetObject, "clone", null);  
  34.                 PropertyUtils.setProperty(cloneTargetObject, "triggerName", triggerName);  
  35.                 jd.getJobDataMap().put("targetObject", cloneTargetObject);  
  36.             } catch (IllegalAccessException e) {  
  37.                 e.printStackTrace();  
  38.             } catch (InvocationTargetException e) {  
  39.                 e.printStackTrace();  
  40.             } catch (NoSuchMethodException e) {  
  41.                 e.printStackTrace();  
  42.             }  
  43.         }  
  44.     }  

具体到job的配置

  1. <bean id="avicinfo.test.testJobService"  
  2.     class="frameworkx.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
  3.     <property name="targetObject"  
  4.         ref="avicinfo.test.testManageService">  
  5.     </property>  
  6.     <property name="group" value="test"></property>  
  7.     <property name="targetMethod">  
  8.         <value>testMethod</value>  
  9.     </property>  
  10.     <property name="concurrent" value="false" />  
  11.     <property name="shouldRecover" value="true" />  
  12. </bean>  
  13. <bean id="avicinfo.test.testManageService"  
  14.     class="com.avicinfo.v2.core.quartz.test.service.impl.MyJobService">  
  15.     <property name="jdbcTemplate" value="jdbcTemplate"></property>  
  16. </bean>  
job的实现

  1. /** 
  2.  * @author lisen 
  3.  * @date Jan 17, 2014 2:07:18 PM 
  4.  */  
  5. public class MyJobService implements Serializable, SchedulerJobDetail, IMyJobService {  
  6.     /** 
  7.      *  
  8.      */  
  9.     private static final long serialVersionUID = 5735518271578346479L;  
  10.   
  11.     private String jdbcTemplate;  
  12.   
  13.     private String triggerName;  
  14.   
  15.     /* 
  16.      * (non-Javadoc) 
  17.      *  
  18.      * @see com.avicinfo.v2.core.quartz.test.service.bo.IMyJobService#testMethod() 
  19.      */  
  20.     @Override  
  21.     public void testMethod() {  
  22.         String sql = "select sysdate from dual";  
  23.         Object result = this.getJdbcTemplateObj().queryForObject(sql, Date.class);  
  24.         System.out.println(result + "  测试job: " + this.getTriggerName() + " "  
  25.                 + this.getClass().getName());  
  26.     }  
  27.   
  28.     /* 
  29.      * (non-Javadoc) 
  30.      *  
  31.      * @see com.avicinfo.v2.core.quartz.service.bo.SchedulerJobDetail#getActionUrl() 
  32.      */  
  33.     @Override  
  34.     public String getActionUrl() {  
  35.         return "quartz/test/testAction.dd";  
  36.     }  
  37.   
  38.     /* 
  39.      * (non-Javadoc) 
  40.      *  
  41.      * @see com.avicinfo.v2.core.quartz.service.bo.SchedulerJobDetail#getDisplayName() 
  42.      */  
  43.     @Override  
  44.     public String getDisplayName() {  
  45.         return "测试job";  
  46.     }  
  47.   
  48.     /** 
  49.      * @return the jdbcTemplate 
  50.      */  
  51.     public String getJdbcTemplate() {  
  52.         return jdbcTemplate;  
  53.     }  
  54.   
  55.     /** 
  56.      * @param jdbcTemplate 
  57.      *            the jdbcTemplate to set 
  58.      */  
  59.     public void setJdbcTemplate(String jdbcTemplate) {  
  60.         this.jdbcTemplate = jdbcTemplate;  
  61.     }  
  62.   
  63.     public JdbcTemplate getJdbcTemplateObj() {  
  64.         return SpringBean.getBean(JdbcTemplate.class, getJdbcTemplate());  
  65.     }  
  66.   
  67.     /* 
  68.      * (non-Javadoc) 
  69.      *  
  70.      * @see com.avicinfo.v2.core.quartz.test.service.bo.IMyJobService#saveConfig(java.util.Map) 
  71.      */  
  72.     @Override  
  73.     public void saveConfig(Map map) {  
  74.         System.out.println("config:" + map);  
  75.         // this.jdbcTemplate.saveConfig .....  
  76.     }  
  77.   
  78.     /* 
  79.      * (non-Javadoc) 
  80.      *  
  81.      * @see com.avicinfo.v2.core.quartz.service.bo.SchedulerJobDetail#setTriggerName(java.lang.String) 
  82.      */  
  83.     @Override  
  84.     public void setTriggerName(String triggerName) {  
  85.         this.triggerName = triggerName;  
  86.     }  
  87.   
  88.     /** 
  89.      * @return the triggerName 
  90.      */  
  91.     public String getTriggerName() {  
  92.         return triggerName;  
  93.     }  
  94.   
  95.     public Object clone() {  
  96.         MyJobService copy;  
  97.         try {  
  98.             copy = (MyJobService) super.clone();  
  99.         } catch (CloneNotSupportedException ex) {  
  100.             throw new IncompatibleClassChangeError("Not Cloneable.");  
  101.         }  
  102.         return copy;  
  103.     }  
  104. }  



本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Quartz使用(一)-入门使用
springboot Quartz 定时任务工具类
Quartz CronTrigger运用
Quartz.NET作业调度框架详解 - leeolevis - 博客园
定时任务框架Quartz详解-基础篇
Java框架介绍:Quartz从入门到进阶
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服