Quartz与Spring的整合-Quartz中的job如何自动注入spring容器托管的对象
对于数据库配置方式的Quartz,配置非常简单,就一个入口类org.springframework.scheduling.quartz.SchedulerFactoryBean。我们这里通过配置它的jobFactory为我们自定义的JobFactory来实现自动注入功能:
<bean /> </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 is?
org.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。
spring的AutowireCapableBeanFactory其实非常强大,Spring3.0允许任何通过Spring配置的bean都可以自动注入它所属的上下文,也就是说默认所有的bean都自动实现了ApplicationContextAware接口,这样就不用显示实现ApplicationContextAware接口了( 是不是更POJO:) ):?How to inject dependencies into a self-instantiated object in Spring?
public class SpringBeanJobFactory extends org.springframework.scheduling.quartz.SpringBeanJobFactory{ @Autowire private AutowireCapableBeanFactory beanFactory; /** * 这里我们覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire。 */ @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object jobInstance = super.createJobInstance(bundle); beanFactory.autowireBean(jobInstance); return jobInstance; }}关于使用ApplicationContextAware和AutowireCapableBeanFactory实现@Autowired功能,在stackoverflow上这个帖子有很详细的说明,可以参考一下:How to get beans created by FactoryBean spring managed?
对于Quartz与Spring的整合问题,spring其实提供了很多内建方案:
org.springframework.scheduling.quartz.JobDetailBean+jobDataAsMap:比如这个:Spring 3 + Quartz 1.8.6 Scheduler Example。不过貌似不推荐.org.springframework.scheduling.quartz.SchedulerFactoryBean+schedulerContextAsMap:比如这个:Quartz and Spring Integration。org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean:这个可以让任何定义在spring中的类成为Quartz要求的job。比如这个:25.6 Using the OpenSymphony Quartz Schedulerorg.springframework.scheduling.quartz.SchedulerFactoryBean+applicationContextSchedulerContextKey:比如这个:Accessing Spring beans from Quartz jobs每种方法笔者都认真的看过,而且找的例子都是非常不错的例子。个人感觉3和4不错,尤其是4。3使用起来有点像spring的事务配置,4使用起来有点像在web层通过WebApplicationContextUtils得到spring的ApplicationContext。不过这几种方式都不是依赖注入,而且配置信息比较多。所以还是推荐上面的org.springframework.scheduling.quartz.SchedulerFactoryBean+AutowireCapableBeanFactory的SpringBeanJobFactory解决方案:)
@Autowired注解大大节省了Spring的xml配置,将bean依赖关系声明转移到类文件和运行期。即: 原来需要这样的配置:
<bean id="thisClass" /> <property name="anotherClass" ref="anotherClass" /></bean><bean id="anotherClass" /></bean><bean id="anotherClass" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="org.springframework.samples.petclinic.web"/> // ...</beans>stackoverflow上有一个非常详细讲解<context:annotation-config>和<context:component-scan>的帖子:?Difference between <context:annotation-config> vs <context:component-scan>。很长,这里就不quote了。简单来说就是两个步骤:
<context:component-scan>?+?@Controller,?@Component, etc.<context:annotation-config/>如果配置了1,那么自动包含2.
当然,回到我们的主题,如果有些bean不应该由Spring托管(不是xml配置,也不是anotation注解+包路径扫描),而是由框架或者应用创建的,那么就需要使用我们一开始介绍的方法来处理了。
—EOF—
?