Quartz与Spring的整合

Quartz中的job如何自动注入spring容器托管的对象

问题

Quartz中的job是由Quartz框架动态创建的(配置该job的classname,通过反射创建),而job一般会依赖到配置在spring中的bean,怎样获取或者更好的自动注入这些依赖bean呢?

预期效果

我们希望达到这样的效果:

/** * * 取消超时未支付订单的任务。 * * @author arganzheng */public class CancelUnpaidOrderTask implements Job {@Autowiredprivate AppOrderService orderService;@Overridepublic void execute(JobExecutionContext ctx) throws JobExecutionException {…}

关键在这一行:

@Autowiredprivate AppOrderService orderService;

orderService是配置在spring容器中的,而CancelUnpaidOrderTask则是配置在Quartz数据库中,由org.springframework.scheduling.quartz.SpringBeanJobFactory运行时调用protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception;方法创建的。

解决方案

Spring提供了一种机制让你可以获取ApplicationContext。就是ApplicationContextAware接口。对于一个实现了ApplicationContextAware接口的类,Spring会实例化它的同时,,调用它的public void setApplicationContext(ApplicationContext applicationContext) throws BeansException;接口,将该bean所属上下文传递给它。

一般利用这个来做ServicesLocator:

public class FooServicesLocator implemnts ApplicationContextAware{private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public static FooService getFooService() {return applicationContext.getBean(FooService.class);}}

当然,你需要在你的xml配置文件中定义FooServicesLocator和FooService。然后在需要引用FooService的地方,就可以这样子获取FooService了:FooServicesLocator.getFoobarServic();得到Spring托管的FooService。

不过这样是依赖查询,不是注入,要实现DI,可以使用AutowireCapableBeanFactory进行autowire。

applicationContext.getAutowireCapableBeanFactory().autowireBean(existingBean);

于是对于上面的那个问题,就有了如下的解决方案:

package me.arganzheng.study.quartz.task.SpringBeanJobFactory;import org.quartz.spi.TriggerFiredBundle;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;/** * 自定义SpringBeanJobFactory,用于对Job注入ApplicationContext等。 * * @author arganzheng */public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.SpringBeanJobFactory implements ApplicationContextAware {private ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}/*** 这里我们覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。*/@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);applicationContext.getAutowireCapableBeanFactory().autowireBean(jobInstance);return jobInstance;}}

然后在Spring中配置Quartz的入口:

<?xml version="1.0" encoding="GBK"?><beans xmlns=""xmlns:xsi=""xsi:schemaLocation=" http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="jobFactory"><bean class="me.arganzheng.study.quartz.task.SpringBeanJobFactory" /></property>…</bean></beans>

对于数据库配置方式的Quartz,配置非常简单,就一个入口类org.springframework.scheduling.quartz.SchedulerFactoryBean。我们这里通过配置它的jobFactory为我们自定义的JobFactory来实现自动注入功能:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="jobFactory"><bean class=”me.arganzheng.study.quartz.task.SpringBeanJobFactory" /></property>…</bean>

注意:上面的XML配置采用了直接配置jobFactory属性的方式将jobFactory配置为我们自定义的jobFactory类,默认是org.springframework.scheduling.quartz.SpringBeanJobFactory。虽然Quartz允许我们通过org.quartz.scheduler.jobFactory.class配置项配置自定义的jobFactory:

org.quartz.scheduler.jobFactory.class

The class name of the JobFactory to use. The default isorg.quartz.simpl.SimpleJobFactory, you may like to tryorg.quartz.simpl.PropertySettingJobFactory. A JobFatcory is responsible for producing instances of JobClasses. SimpleJobFactory simply calls newInstance() on the class. PropertySettingJobFactory does as well, but also reflectively sets the job’s bean properties using the contents of the JobDataMap.

但是注意到我们配置的是Spring封装的是org.springframework.scheduling.quartz.SchedulerFactoryBean,它并不认这个配置项目。因为它已经将它的jobFactory由org.quartz.simpl.SimpleJobFactory改为org.springframework.scheduling.quartz.SpringBeanJobFactory,所以只能采用配置jobFactory属性的方式修改jobFactory为我们的自定义factory。

对的,坚持;错的,放弃!

Quartz与Spring的整合

相关文章:

你感兴趣的文章:

标签云: