spring和quartz的集成

一直以来都认为spring对quartz的支持不是特别合理,每一个定时任务需要配置多达三个bean,一个targetObject,一个Jobdetail,一个trigger。今天自己实现了一个简单的spring对quartz的支持,一个任务只需要配置一个spring bean即可,bean仅有一个必要属性,cronExpression(触发条件表达式)。

 

 

先贴出核心类

package com.crunii.emall.quartz;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.BeanNameAware;

public abstract class QuartzJob extends JobDetail implements Job, BeanNameAware {

	private String beanName;

	public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException {
 		run();
	}

	private String cronExpression;
	protected Log log = LogFactory.getLog(this.getClass());

	public String getCronExpression() {
		return cronExpression;
	}

	public void setCronExpression(String cronExpression) {
		this.cronExpression = cronExpression;
	}

	public abstract void run();

	public void setBeanName(String beanName) {
		super.setGroup(beanName);
		super.setName(beanName);
		super.setJobClass(this.getClass());
		this.beanName = beanName;

	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("cronExpression", this.cronExpression)
				.toString();
	}

	public String getBeanName() {
		return beanName;
	}

}

 

每一个需要定时执行的任务都要继承这个类,run方法里面是具体的业务代码

 

package com.crunii.emall.quartz;

import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.quartz.simpl.SimpleJobFactory;
import org.quartz.spi.TriggerFiredBundle;

public class SpringBeanJobFactory extends SimpleJobFactory {

	@SuppressWarnings("unchecked")
	public Job newJob(TriggerFiredBundle triggerfiredbundle) throws SchedulerException {
		JobDetail jobDetail = triggerfiredbundle.getJobDetail();
		if (jobDetail instanceof QuartzJob && jobDetail instanceof Job) {
			return (Job) jobDetail;
		} else {
			return super.newJob(triggerfiredbundle);
		}
	}

}

 

这个东西困扰了我很久,quartz在定制任务的时候,默认是自动把jobdetail里面的class做newinstance,个人觉得这个做法不太合理,应该开放一个api来实现可以放入具体的Object,而不是class。因为有的时候我需要自己来生成需要执行的object,比如在和spring集成的时候,我就需要将spring里面的bean直接放入到quartz工厂,而quartz显然不支持这个做法。

 

 

 

 

下面从spring工厂里面取得需要定时执行的object,放入到quartz工厂

		try {
			SchedulerFactory schedFact = new StdSchedulerFactory();
			sched = schedFact.getScheduler();
			// 这里需要重写jobfactory,不然springbean放入进去之后,所有spring注入的属性都不能用,nullpointer
                         SpringBeanJobFactory jobfactory = new SpringBeanJobFactory();
			sched.setJobFactory(jobfactory);
			sched.start();
			Map<String, QuartzJob> quartzTasks = context.getBeansOfType(QuartzJob.class);
			for (QuartzJob quartzJob : quartzTasks.values()) {
				String beanName = quartzJob.getBeanName();
				CronTrigger trigger = new CronTrigger(beanName, beanName);
				try {
					trigger.setCronExpression(quartzJob.getCronExpression());
				} catch (ParseException e) {
					e.printStackTrace();
				}
				sched.scheduleJob(quartzJob, trigger);
			} 
		} catch (SchedulerException e) {
			e.printStackTrace();
		}

 

 

 

最后还是贴一下具体的用法吧

这里我没有引入其他的bean,不过显然上面的SpringBeanJobFactory已经实现了这个功能了。 

 

	<bean id="quartzBeanTest" class="com.crunii.emall.task.service.quartz.QuartzBeanTest">
 		<property name="cronExpression" value="0/10 * * * * ? "></property>
	</bean>
 

 

 

 

package com.crunii.emall.task.service.quartz;

import com.crunii.emall.quartz.QuartzJob;

public class QuartzBeanTest extends QuartzJob{

	@Override
	public void run() {

		log.info("test");

		
	}
}
 

这里没有详细的考虑过线程的问题,欢迎各个大神拍砖 

你可能感兴趣的:(spring)