Quartz与Spring集成 Job如何自动注入Spring容器托管的对象

 

在Spring中使用Quartz有两种方式实现:
第一种是任务类继承QuartzJobBean,
第二种则是在配置文件里定义任务类和要执行的方法,类和方法可以是普通类。很显然,第二种方式远比第一种方式来的灵活。

 

测试环境 Spring3 M2 quartz-2.1.7

我们要达到这样的效果

public class CancelUnpaidOrderTask implements Job {
    @Autowired
    private AppOrderService orderService;

    @Override
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
        ...
}

但是Job对象的实例化过程是在Quartz中进行的,AppOrderService是在Spring容器当中的,那么如何将他们关联到一起呢。好在Quartz提供了JobFactory接口,让我们可以自定义实现创建Job的逻辑。

public interface JobFactory {
    Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException;
}

那么我们通过实现JobFactory 接口,在实例化Job以后,在通过ApplicationContext 将Job所需要的属性注入即可

在Spring与Quartz集成时 用到的是org.springframework.scheduling.quartz.SchedulerFactoryBean这个类。源码如下,我们只看最关键的地方。

        // Get Scheduler instance from SchedulerFactory.
        try {
            this.scheduler = createScheduler(schedulerFactory, this.schedulerName);
            populateSchedulerContext();

            if (!this.jobFactorySet && !(this.scheduler instanceof RemoteScheduler)) {
                // Use AdaptableJobFactory as default for a local Scheduler, unless when
                // explicitly given a null value through the "jobFactory" bean property.
                this.jobFactory = new AdaptableJobFactory();
            }
            if (this.jobFactory != null) {
                if (this.jobFactory instanceof SchedulerContextAware) {
                    ((SchedulerContextAware) this.jobFactory).setSchedulerContext(this.scheduler.getContext());
                }
                this.scheduler.setJobFactory(this.jobFactory);
            }
        }

其中红色标记的是重点,如果我们不指定jobFactory,那么Spring就使用AdaptableJobFactory。我们在来看一下这个类的实现

package org.springframework.scheduling.quartz;

import java.lang.reflect.Method;

import org.quartz.Job;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.spi.JobFactory;
import org.quartz.spi.TriggerFiredBundle;

import org.springframework.util.ReflectionUtils;

public class AdaptableJobFactory implements JobFactory {

    public Job newJob(TriggerFiredBundle bundle, Scheduler scheduler) throws SchedulerException {
        return newJob(bundle);
    }

    public Job newJob(TriggerFiredBundle bundle) throws SchedulerException {
        try {
            Object jobObject = createJobInstance(bundle);
            return adaptJob(jobObject);
        }
        catch (Exception ex) {
            throw new SchedulerException("Job instantiation failed", ex);
        }
    }

    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // Reflectively adapting to differences between Quartz 1.x and Quartz 2.0...
        Method getJobDetail = bundle.getClass().getMethod("getJobDetail");
        Object jobDetail = ReflectionUtils.invokeMethod(getJobDetail, bundle);
        Method getJobClass = jobDetail.getClass().getMethod("getJobClass");
        Class jobClass = (Class) ReflectionUtils.invokeMethod(getJobClass, jobDetail);
        return jobClass.newInstance();
    }

    protected Job adaptJob(Object jobObject) throws Exception {
        if (jobObject instanceof Job) {
            return (Job) jobObject;
        }
        else if (jobObject instanceof Runnable) {
            return new DelegatingJob((Runnable) jobObject);
        }
        else {
            throw new IllegalArgumentException("Unable to execute job class [" + jobObject.getClass().getName() +
                    "]: only [org.quartz.Job] and [java.lang.Runnable] supported.");
        }
    }

}

其他的我们都不管,我们就看红色的地方,这里是创建了一个Job,那我们就在这里去给Job的属性进行注入就可以了,让我们写一个类继承它,然后复写这个方法进行对Job的注入。

public class MyJobFactory extends AdaptableJobFactory {

    //这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);
        //进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

接下来把他配置到Spring当中去

<bean id="jobFactory" class="com.gary.operation.jobdemo.demo1.MyJobFactory"></bean>

然后在把org.springframework.scheduling.quartz.SchedulerFactoryBean的jobFactory设置成我们自己的。

<bean name="MyScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  <!-- 其他属性省略 -->
  <property name="jobFactory" ref="jobFactory"></property>
</bean>

这样就完成了Spring对Job的注入功能,其实很简单,原理就是在我们扩展JobFactory创建job的方法,在创建完Job以后进行属性注入。

http://www.cnblogs.com/daxin/p/3608320.html

https://github.com/helloworldtang/ch6_2_3/tree/master/src/main/java/com/schedule/quartz

http://my.oschina.net/hhaijun/blog/698498

http://blog.csdn.net/fenglibing/article/details/6847158
http://blog.csdn.net/whaosy/article/details/6298686

 

时间: 2024-10-01 01:10:28

Quartz与Spring集成 Job如何自动注入Spring容器托管的对象的相关文章

Spring 4.0.2 学习笔记(2) - 自动注入及properties文件的使用

接上一篇继续, 学习了基本的注入使用后,可能有人会跟我一样觉得有点不爽,Programmer的每个Field,至少要有一个setter,这样spring配置文件中才能用<property>...</property>来注入. 能否不要这些setter方法? 答案是Yes 一.为Spring配置文件,添加annotation支持,以及 default-autowire属性 <?xml version="1.0" encoding="UTF-8&qu

MyBatis5中Spring集成MyBatis事物管理_java

单独使用MyBatis对事物进行管理 前面MyBatis的文章有写过相关内容,这里继续写一个最简单的Demo,算是复习一下之前MyBatis的内容吧,先是建表,建立一个简单的Student表: create table student ( student_id int auto_increment, student_name varchar(20) not null, primary key(student_id) ) 建立实体类Student.java: public class Studen

spring 集成quazt 后如何实现等spring容器加载完成之后自动执行一次任务?

问题描述 我的项目中使用了spring集成quazt来实现任务调度任务的功能,现在有这样一个需求,我需要通过后台任务每隔半小时统计一次业务数据,然后放到缓存中,前台页面通过实时刷新页面来从缓存中获取统计的数据,可能,当我们系统刚上线的时候调度任务还没有执行,要等到指定的时间点才执行,我现要想让系统等到spring容器加载完成后就自动执行一次,请问有什么办法吗?<bean id="refreshOldAccountTrigger" class="org.springfra

spring集成quartz时不执行问题

问题描述 我用spring集成quartz,用的是cronExpress,当我设置成<property name="cronExpression" value="0 38 * * * ?"></property>,即不设置小时数时,正常执行,当我设置成<property name="cronExpression" value="0 38 8 * * ?"></property>代

定时器 quartz 与spring集成时的问题

问题描述 quartz在于spring集成时,需要配置<beanid="jobDetail"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><propertyname="targetObject"ref="simpleService"/><propertyname="targ

hibernate spring 自动注入报错

问题描述 - Context initialization failedorg.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityManager': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: C

Activiti学习——Activiti与Spring集成

与Spring集成 基础准备 目录结构 相关jar包 Activiti的相关jar包 Activiti依赖的相关jar包 Spring的相关jar包 Spring依赖的相关jar包 本示例相关jar包截图   配置文件设置 web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&

shiro和spring集成时session管理器超时时间问题

问题描述 shiro和spring集成时session管理器超时时间问题 这是我的配置文件,我配置了并发人数控制和动态权限过滤,然后session超时时间这里也是配置了的,然后并没有什么鸟用,在登录以后获取超时时间也是正常的,但还是1分钟就过期了. <?xml version="1.0" encoding="UTF-8"?> xmlns:util="http://www.springframework.org/schema/util"

一个简单的hibernate与spring集成

下面介绍一下hibernate与spring的集成,这两个框架的集成关键在于 applicationContext.xml文件的配置,其实很简单的,但需要注意的是,导入包 时一定选择导入到webroot/web-inf/lib目录中,而且hibernate一般要在spring 之前导入,因为集成时要用到sessionFactory类, 一.初始化工作:新建一个项目,如(ssh),在此项目中导入对hibernate的支持 ,新建一个表sstest表,有字段id,username,password,