年前做了个触发器管理,将以前设计不合理的地方修改掉了。
所谓动态创建,就是触发器的时间、触发器的任务由用户自己去设定,当然这个任务还是需要开发人员手动去写。
以前同事做的触发器管理,将某个任务写死,没法做到扩展,也没有持久化方面的考虑
后来参考 http://sundoctor.iteye.com/blog/399980 中提到的持久化方法,进行修改,已经满足要求。
本文使用的是quartz的1.7版本,quartz好像是分为两部分,一部分是任务(job)一个是触发器(trigger);trigger运行过程中,达到触发时间条件,将会执行job。
触发器管理模块需要提供触发器动态创建、删除、暂停、恢复功能,并结合spring做到job的扩展
在与spring整合时,有两个配置项 jobDetails和triggers
- <bean id="schedulerFactory" lazy-init='false'
- class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
-
- <property name="dataSource" ref="dataSource" />
- <property name="applicationContextSchedulerContextKey"
- value="applicationContextKey" />
- <property name="configLocation"
- value="classpath:quartz.properties" />
- <property name="startupDelay" value="30" />
-
- <!-- property name="overwriteExistingJobs" value="true" / -->
- <!-- 可用的job列表 -->
- <property name="jobDetails">
- <list>
- <!-- 示例 -->
- <ref bean="avicinfo.test.testJobService" />
- </list>
- </property>
-
- <!-- 默认启动的trigger列表 -->
- <property name="triggers">
- <list>
- <ref bean="OnlineDocDeleteRubbishFilesJobTrigger" />
- </list>
- </property>
- </bean>
triggers中配置的信息已经是完整的触发器了,包含时间、job等信息,这部分会在SchedulerFactoryBean生成Scheduler对象时,就已经加载到触发器列表中了。
jobDetails是job的配置部分,想要做到由用户选择触发什么job,就要从这里入手。
通过quartz的api了解到,我使用的这个版本,没有直接提供获取所有job的方法,而是可以通过查找所有jobGroupName,得到最后的job对象,而在我的触发器管理模块中,默认启动的trigger是不能被删除的,所以将这些trigger中job的group不做设置,即默认组(DEFAULT),而其他在jobDetails中配置的job需要强制设定组信息,并且还要实现固定的接口,以达到对这些动态创建trigger的管理。
获取可以用于动态创建的job
- public List<JobDetail> getCanUseQrtzJobs() throws SchedulerException {
- List<JobDetail> list = new ArrayList<JobDetail>();
- String[] jobGroupNames = this.scheduler.getJobGroupNames();
- for (String jobGroupName : jobGroupNames) {
- // 去掉受保护的分组
- if (!CANNOT_USE_GROUPS.contains(jobGroupName)) {
- String[] jobNames = this.scheduler.getJobNames(jobGroupName);
- for (String jobName : jobNames) {
- JobDetail jd = this.scheduler.getJobDetail(jobName, jobGroupName);
- // 获取实际调度对象
- Object targetObject = jd.getJobDataMap().get("targetObject");
- if (StaticMethod.hasInterface(targetObject.getClass(), CAN_USE_INTERFACES)) {
- try {
- Object obj = PropertyUtils.getProperty(targetObject, "triggerName");
- if (StaticMethod.isEmpty(obj)) {
- list.add(jd);
- }
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
-
- }
- }
- }
- }
- return list;
- }
job需要实现的接口,提供管理连接,和唯一标识这个trigger的属性,我使用的是triggerName,全局唯一。
- /**
- * @author lisen
- * @date Jan 17, 2014 1:56:42 PM
- */
- public interface SchedulerJobDetail extends Cloneable {
-
- /**
- * 获得展现页面的地址 不包括ip 端口号 工程名
- *
- * @return
- */
- String getActionUrl();
-
- /**
- * 显示名称
- *
- * @return
- */
- String getDisplayName();
-
- /**
- * 设置触发器名 对象唯一识别
- *
- * @param triggerName
- */
- void setTriggerName(String triggerName);
-
- /**
- * 获取触发器名
- *
- * @return
- */
- String getTriggerName();
-
- }
在启动一个trigger时,可以根据选择的jobName,jobGroup,获取到这个job的配置对象,将它塞到创建的trigger对象中,但是在这个trigger执行完毕后,他的job也随之被释放了,持久化的对象被删除。而quartz提供的持久化方法,仅仅判断jobName和jobGroup,所以在创建时,要在获取配置中得到job的name做下手脚,让他变成一个唯一对象,这样,trigger的生命周期如何,都和我们配置job没有关系了
- @Override
- public void schedule(String triggerName, String triggerGroup, String jobDetailName,
- String jobDetailGroup, String cronExpression, boolean overwriteExistingTrigger) {
- try {
- // 保证有这个job
- JobDetail tjd = this.scheduler.getJobDetail(jobDetailName, jobDetailGroup);
- if (!StaticMethod.isEmpty(tjd)) {
- JobDetail jd = (JobDetail) tjd.clone();
- // 处理获取到的job
- handleJobDetail(jd, triggerName);
- this.scheduler.addJob(jd, true);
- Trigger t = this.scheduler.getTrigger(triggerName, triggerGroup);
- if (!StaticMethod.isEmpty(t) && overwriteExistingTrigger) {
- this.removeTrigger(triggerName, triggerGroup);
- }
- CronTrigger cronTrigger = new CronTrigger(triggerName, triggerGroup, jd.getName(),
- jd.getGroup());
- cronTrigger.setCronExpression(cronExpression);
- this.scheduler.scheduleJob(cronTrigger);
- }
- } catch (Exception e) {
- throw new SchedulerRuntimeException(e);
- }
- }
-
- protected void handleJobDetail(JobDetail jd, String triggerName) {
- jd.setDescription(jd.getName());
- jd.setName(UUID.randomUUID().toString());
- // 获取实际调度对象
- Object targetObject = jd.getJobDataMap().get("targetObject");
- if (StaticMethod.hasInterface(targetObject.getClass(), CAN_USE_INTERFACES)) {
- try {
- Object cloneTargetObject = MethodUtils.invokeMethod(targetObject, "clone", null);
- PropertyUtils.setProperty(cloneTargetObject, "triggerName", triggerName);
- jd.getJobDataMap().put("targetObject", cloneTargetObject);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- }
- }
- }
具体到job的配置
- <bean id="avicinfo.test.testJobService"
- class="frameworkx.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
- <property name="targetObject"
- ref="avicinfo.test.testManageService">
- </property>
- <property name="group" value="test"></property>
- <property name="targetMethod">
- <value>testMethod</value>
- </property>
- <property name="concurrent" value="false" />
- <property name="shouldRecover" value="true" />
- </bean>
- <bean id="avicinfo.test.testManageService"
- class="com.avicinfo.v2.core.quartz.test.service.impl.MyJobService">
- <property name="jdbcTemplate" value="jdbcTemplate"></property>
- </bean>
job的实现
![](//pubimage.360doc.com/wz/default.gif)
![](//pubimage.360doc.com/wz/default.gif)
![](//pubimage.360doc.com/wz/default.gif)
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。