Spring+ quartz 之 多任务动态定时(任务中伏任务)
Spring+ quartz 之 多任务动态定时(任务中起任务)
参见上一篇Spring+ quartz 多任务定时 执行 与cronExpression表达式 可以知道如何设置多个规则的定时任务,但有时需要客户自己设置指定的时间来启动新的任务处理不同的事情。
实现方式:用户在前台自行维护任务列表和任务执行时间,后台将任务执行时间解析成对应的cronexpression后与任务列表一起保存到数据库中。在 服务器运行期间添加的任务通过验证的(quartz会验证cronexpression是否合法以及对应时间是否已经过期)将直接添加一个任务以及触发器。
简而言之,就是自己创建一个新的jobdetail ---新的 Trigger 指定行的定时规则--启动新增定时器任务 (执行完新任务可以选择取消新的任务)
这里实现的思路是:按照定时规则扫描用户设置的任务开始时间,如定时发短信,有定时的就发出去。
1、首先加入定时规则扫描的任务,
package net.nilm61.timeTask; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Locale; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import net.nilm61.entity.Repay; import net.nilm61.service.RepayService; import org.quartz.CronTrigger; import org.quartz.JobDetail; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.springframework.context.ApplicationContext; import org.springframework.orm.jpa.EntityManagerHolder; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.transaction.support.TransactionSynchronizationManager; public class AutoRepayBidTask extends QuartzJobBean{ private RepayService repayService; public void setRepayService(RepayService repayService) { this.repayService = repayService; } @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { EntityManagerFactory emf = null; EntityManager em = null; //System.out.println("Start!!!!!!!!!"); try{ Scheduler scheduler = context.getScheduler(); ApplicationContext ac = (ApplicationContext)scheduler.getContext().get("theScheduler"); emf = (EntityManagerFactory) ac.getBean("entityManagerFactory", EntityManagerFactory.class); em = emf.createEntityManager(); TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em)); RepayService repayService = (RepayService)ac.getBean("recordService"); setRepayService(repayService); doBiz(scheduler); }catch(Exception e){ e.printStackTrace(); //logger.error(e.getMessage()); }finally{ //System.out.println("over!!!!!!!!!!!!!!!!!"); if(em!=null){ em.close(); } } } private void doBiz(Scheduler scheduler) { try{ List<Repay> repays = repayService.getByAutoRepay(); //从数据库中查询定时处理的条目 if(repays != null && repays.size() >0){ DateFormat df = new SimpleDateFormat("ss mm HH dd MM ? yyyy ",Locale.ENGLISH); for(Repay repay : repays){ Date actualTime =repay.getActualTime(); if(actualTime != null){ String cronExpression = df.format(actualTime); //新建任务,任务组为默认的Scheduler.DEFAULT_GROUP,需要执行的任务类为DoBiz4TestTask.class JobDetail jobDetail = new JobDetail("AutoRepayBidsJob_" + repay.getId(), Scheduler.DEFAULT_GROUP, DoBiz4TestTask.class); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger( "AutoRepayBidsTrigger_"+repay.getId(), Scheduler.DEFAULT_GROUP); if(cronTrigger == null){ //新建触发器,触发器为默认的Scheduler.DEFAULT_GROUP cronTrigger = new CronTrigger("AutoRepayBidsTrigger_" + repay.getId(), Scheduler.DEFAULT_GROUP); } //为触发器设置定时表达式 cronTrigger.setCronExpression(cronExpression); // System.out.println(cronExpression); try{ //启动新增定时器任务 scheduler.scheduleJob(jobDetail, cronTrigger); }catch(SchedulerException e){ //启动验证失败,设置任务标记为禁用 e.printStackTrace(); } } } } }catch(Exception e){ e.printStackTrace(); } } }
2.增加DoBiz4TestTask (具体执行的定时任务)
所有的触发器执行的任务类均为DoBiz4TestTask.class,DoBiz4TestTask 需要实现接口:org.quartz.Job中的方法execute方法,这里继承的是org.quartz.Job的子类org.springframework.scheduling.quartz.QuartzJobBean 参考代码如下
package net.nilm61.timeTask; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.Scheduler; import org.quartz.Trigger; import org.springframework.context.ApplicationContext; import org.springframework.orm.jpa.EntityManagerHolder; import org.springframework.scheduling.quartz.QuartzJobBean; import org.springframework.transaction.support.TransactionSynchronizationManager; public class DoBiz4TestTask extends QuartzJobBean{ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { EntityManagerFactory emf = null; EntityManager em = null; try{ Scheduler scheduler = context.getScheduler(); ApplicationContext ac = (ApplicationContext)scheduler.getContext().get("theScheduler"); Trigger trigger = context.getTrigger(); emf = (EntityManagerFactory) ac.getBean("entityManagerFactory", EntityManagerFactory.class); em = emf.createEntityManager(); TransactionSynchronizationManager.bindResource(emf, new EntityManagerHolder(em)); doBiz(scheduler,trigger); }catch(Exception e){ e.printStackTrace(); //logger.error(e.getMessage()); }finally{ if(em!=null){ em.close(); } } } private void doBiz(Scheduler scheduler,Trigger trigger) { try{ //获取触发器名称 String triggerName = trigger.getName(); //根据触发器名称得到对应的任务Id // Integer id = Integer.valueOf(triggerName.split("_")[1]); //处理指定的任务 //TODO: ... System.out.println("triggerName === "+triggerName); //根据触发器名称得到对应的任务Id if(null != trigger){ //执行完移除该任务 scheduler.unscheduleJob(trigger.getName(), trigger.getGroup()); } }catch(Exception e){ e.printStackTrace(); } } }
3.配置文件中加入
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="net.nilm61.timeTask.DoAutoRepayBidTask"/> <!-- <property name="jobDataMap" ></property> --> </bean> <bean id="DoBiz4TestTask" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="net.nilm61.timeTask.DoBiz4TestTask"/> <!-- <property name="jobDataMap" ></property> --> </bean> <bean id="AutoRepayTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail"/> <property name="cronExpression" value="0 0/1 14-18 * * ?"/> </bean> <bean id="DoBiz4TestTaskss" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="DoBiz4TestTask"/> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="AutoRepayTrigger"/> </list> </property> <property name="applicationContextSchedulerContextKey"> <value>theScheduler</value> </property> </bean>