2014-05-18 12:51 by Jeff Lihtml
系列文章:[傳送門]java
項目需求:spring
http://www.cnblogs.com/Alandre/p/3733249.html數據庫
上一博客寫的是基本調度,後來這隻能用於,像天天定個時間 進行數據庫備份。可是,遠遠不能在上次的需求上實現。因此須要實現spring4.0 整合 Quartz 實現動態任務調度。api
spring4.0 整合 Quartz 實現任務調度。這真是期末項目的最後一篇,剩下到暑假吧。app
Quartz is a full-featured, open source job scheduling service that can be integrated with, or used along side virtually any Java application - from the smallest stand-alone application to the largest e-commerce system. Quartz can be used to create simple or complex schedules for executing tens, hundreds, or even tens-of-thousands of jobs; 框架
Quartz框架是一個全功能、開源的任務調度服務,能夠集成幾乎任何的java應用程序—從小的單片機系統到大型的電子商務系統。Quartz能夠執行上千上萬的任務調度。less
核心概念ide
Quartz核心的概念:scheduler任務調度、Job任務、Trigger觸發器、JobDetail任務細節post
相關文檔:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/quick-start
上次咱們配置了
<!--Quartz--> <!-- 集成方式:JobDetailFactoryBean,而且任務類須要繼承QuartzJobBean--> <!-- 定義jobDetail --> <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- durability 表示任務完成以後是否依然保留到數據庫,默認false --> <property name="durability" value="true" /> <!-- 目標類 /wmuitp/src/test/SpringQuartz.java--> <property name="jobClass" value="test.SpringQuartzTest"></property> <!-- 在這個例子中,jobDataAsMap沒有用,此目標類中接受的參數 ,若參數爲service,則能夠在此進行參數配置,相似struts2 --> <!-- <property name="jobDataAsMap"> <map> <entry key="service"><value>simple is the beat</value></entry> </map> </property> --> </bean> <!-- 定義simpleTrigger觸發器 --> <!-- <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="jobDetail"></property> <property name="repeatCount"> <value>8</value> </property> <property name="repeatInterval"> <value>1000</value> </property> <property name="startDelay"> <value>4</value> </property> </bean> --> <!-- 另外一種觸發器是CornTrigger --> <bean id="cornTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="jobDetail"/> <!-- 每一個10秒觸發 --> <property name="cronExpression" value="0/10 * * * * ?"/> </bean> <!-- 定義核心調度器 --> <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <ref bean="cornTrigger"/> </property> </bean>
#spring實現quartz的方式,先看一下上面配置文件中定義的jobDetail。在Quartz 2.x版本中JobDetail已是一個接口,Spring是經過將其轉換爲MethodInvokingJob或StatefulMethodInvokingJob類型來實現的。
這是文檔中的源碼:
/** * This implementation applies the passed-in job data map as bean property * values, and delegates to <code>executeInternal</code> afterwards. * @see #executeInternal */public final void execute(JobExecutionContext context) throws JobExecutionException { try { // Reflectively adapting to differences between Quartz 1.x and Quartz 2.0... Scheduler scheduler = (Scheduler) ReflectionUtils.invokeMethod(getSchedulerMethod, context); Map mergedJobDataMap = (Map) ReflectionUtils.invokeMethod(getMergedJobDataMapMethod, context); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValues(scheduler.getContext()); pvs.addPropertyValues(mergedJobDataMap); bw.setPropertyValues(pvs, true); } catch (SchedulerException ex) { throw new JobExecutionException(ex); } executeInternal(context); } /** * Execute the actual job. The job data map will already have been * applied as bean property values by execute. The contract is * exactly the same as for the standard Quartz execute method. * @see #execute */protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException;
MethodInvokingJobDetailFactoryBean中的源碼:
public void afterPropertiesSet() throws ClassNotFoundException, NoSuchMethodException { prepare(); // Use specific name if given, else fall back to bean name. String name = (this.name != null ? this.name : this.beanName); // Consider the concurrent flag to choose between stateful and stateless job. Class jobClass = (this.concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class); // Build JobDetail instance. if (jobDetailImplClass != null) { // Using Quartz 2.0 JobDetailImpl class... this.jobDetail = (JobDetail) BeanUtils.instantiate(jobDetailImplClass); BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this.jobDetail); bw.setPropertyValue("name", name); bw.setPropertyValue("group", this.group); bw.setPropertyValue("jobClass", jobClass); bw.setPropertyValue("durability", true); ((JobDataMap) bw.getPropertyValue("jobDataMap")).put("methodInvoker", this); } else { // Using Quartz 1.x JobDetail class... this.jobDetail = new JobDetail(name, this.group, jobClass); this.jobDetail.setVolatility(true); this.jobDetail.setDurability(true); this.jobDetail.getJobDataMap().put("methodInvoker", this); } // Register job listener names. if (this.jobListenerNames != null) { for (String jobListenerName : this.jobListenerNames) { if (jobDetailImplClass != null) { throw new IllegalStateException("Non-global JobListeners not supported on Quartz 2 - " + "manually register a Matcher against the Quartz ListenerManager instead"); } this.jobDetail.addJobListener(jobListenerName); } } postProcessJobDetail(this.jobDetail); }
#既然知道了其因此然,咱們就能夠真正實戰了。
聽我慢慢道來
爲了實現一個定時任務,spring的配置代碼太多了。動態配置須要們手動來搞。這裏咱們只須要這要配置便可:
<!-- quartz配置 動態配置因此咱們將 Factory 做爲一個service同樣的接口 QuartzJobFactory.java--> <!-- 調度工廠 --> <bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> </bean>
在這裏我把它看做工廠類:
QuartzJobFactoryImpl execute(JobExecutionContext context) "任務成功運行"= (ScheduleJob)context.getMergedJobDataMap().get("scheduleJob""任務名稱 = [" + scheduleJob.getJobName() + "]"
package test;public class ScheduleJob { /** 任務id **/ private String jobId; /** 任務名稱 **/ private String jobName; /** 任務分組 **/ private String jobGroup; /** 任務狀態 0禁用 1啓用 2刪除**/ private String jobStatus; /** 任務運行時間表達式 **/ private String cronExpression; /** 任務描述 **/ private String desc; public String getJobId() { return jobId; } public void setJobId(String jobId) { this.jobId = jobId; } public String getJobName() { return jobName; } public void setJobName(String jobName) { this.jobName = jobName; } public String getJobGroup() { return jobGroup; } public void setJobGroup(String jobGroup) { this.jobGroup = jobGroup; } public String getJobStatus() { return jobStatus; } public void setJobStatus(String jobStatus) { this.jobStatus = jobStatus; } public String getCronExpression() { return cronExpression; } public void setCronExpression(String cronExpression) { this.cronExpression = cronExpression; } public String getDesc() { return desc; } public void setDesc(String desc) { this.desc = desc; } }
下面咱們就來測試下:
Controller 測試代碼:
@RequestMapping(value = "/quartz") public ModelAndView quartz() throws SchedulerException { //schedulerFactoryBean 由spring建立注入 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println(ctx); Scheduler scheduler = (Scheduler)ctx.getBean("schedulerFactoryBean"); System.out.println(scheduler); //這裏獲取任務信息數據 List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(); for (int i = 0; i < 3; i++) { ScheduleJob job = new ScheduleJob(); job.setJobId("10001" + i); job.setJobName("JobName_" + i); job.setJobGroup("dataWork"); job.setJobStatus("1"); job.setCronExpression("0/5 * * * * ?"); job.setDesc("數據導入任務"); jobList.add(job); } for (ScheduleJob job : jobList) { TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup()); //獲取trigger,即在spring配置文件中定義的 bean id="myTrigger" CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); //不存在,建立一個 if (null == trigger) { JobDetail jobDetail = JobBuilder.newJob(QuartzJobFactoryImpl.class) .withIdentity(job.getJobName(), job.getJobGroup()).build(); jobDetail.getJobDataMap().put("scheduleJob", job); //表達式調度構建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job .getCronExpression()); //按新的cronExpression表達式構建一個新的trigger trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail, trigger); } else { // Trigger已存在,那麼更新相應的定時設置 //表達式調度構建器 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job .getCronExpression()); //按新的cronExpression表達式從新構建trigger trigger = trigger.getTriggerBuilder().withIdentity(triggerKey) .withSchedule(scheduleBuilder).build(); //按新的trigger從新設置job執行 scheduler.rescheduleJob(triggerKey, trigger); } } ModelAndView mav = new ModelAndView(AdminWebConstant.ADMIN_LOGIN_VIEW); return mav; }
#後面這塊應該會進一步整理。到時候 會出個更詳細的。期待吧
測試結果:
spring quartz
http://url.cn/RzETYu 加入個人羣
路上走來一步一個腳印,但願你們和我一塊兒。
感謝讀者!很喜歡大家給個人支持。若是支持,點個贊。
知識來源: 《spring in action》 quartz api