QuartZ和Spring整合

来源:互联网 发布:mac 图片处理 编辑:程序博客网 时间:2024/06/06 20:08

Spring 版本: 2.5

QuartZ 版本  1.6.6


Spring整合QuartZ算是非常简单的.

创建一个Bean即可.

    <bean name="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">        <property name="dataSource" ref ="dataSource" />        <property name="applicationContextSchedulerContextKey" value="applicationContextKey"/>        <!--这个是必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动-->          <property name="startupDelay" value="30"/>        <!--这个是可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了-->          <property name="overwriteExistingJobs" value="true"/>         <property name="configLocation" value="classpath:timer.properties"/>    </bean>    

timer.properties中的内容,就是QuartZ快速入门中的内容

定义一个服务,把调度器注入进去

    <bean id="schedulingService" class="xxx.SchedulingServiceImpl">        <property name="scheduler" ref ="quartzScheduler" />    </bean>

下面是一个实现的调度器例子:定时上下架

定时上下架的class

public class ProdUpAndDownImpl {private SchedulingService schedulingService_;    private String cronExpression_;        public void setSchedulingService(SchedulingService schedulingService) {        this.schedulingService_ = schedulingService;    }    public void setCronExpression(String cronExpression) {        this.cronExpression_ = cronExpression;    }    public void init() {        schedulingService_.scheduleJob("prodUpdownTask", null, "prodUpdownTask", cronExpression_);    }}

通过bean注入参数

    <!-- 定时上下架 -->    <bean id="prodUpdownListener" class="xxx.ProdUpAndDownImpl" init-method="init">        <property name="schedulingService" ref ="schedulingService" />        <property name="cronExpression" value ="0 0/15 * * * ?" />    </bean>    


cornExpression 具体请查看 表达式示例

下面是Service具体的调用

    public void scheduleJob(String jobName, Object[] arguments, String triggerName, String cronExpression) throws SchedulingException {        scheduleJob(jobName, arguments, triggerName, cronExpression, Scheduler.DEFAULT_GROUP);    }    /**     * 根据 Quartz Cron Expression 调度任务     * @param jobName  调度任务需要执行的服务     * @param arguments  任务参数(必须可序列化)     * @param triggerName  触发器名称     * @param cronExpression Quartz Cron 表达式,如 "0/10 * * ? * * *"等     * @param triggerGroup 触发器组名称     */    public void scheduleJob(String jobName, Object[] arguments, String triggerName, String cronExpression, String triggerGroup) {        JobDetail jobDetail = (JobDetail) context_.getBean(jobName);                if (arguments != null) {            jobDetail.getJobDataMap().put("arguments", arguments);        }        // 使用TriggerName作为作业名jobDetail.setName(triggerName);// 调度器增加一个job,true表示替换.scheduler_.addJob(jobDetail, true);// 具体触发CronTrigger cronTrigger = new CronTrigger(triggerName, triggerGroup, jobDetail.getName(),Scheduler.DEFAULT_GROUP);// 触发的表达式cronTrigger.setCronExpression(cronExpression);// 获取这个触发实例if (scheduler_.getTrigger(triggerName, triggerGroup) == null) {// 给触发器添加标示scheduler_.scheduleJob(cronTrigger);} else {// 重置对应的触发器.scheduler_.rescheduleJob(triggerName, triggerGroup, cronTrigger);}    }


下面是具体的任务类 prodUpdownTask的Bean

     <!-- 定时上下架 -->     <bean id="prodUpdownTask" class="xxx.MethodInvokingJobDetailFactoryBean">        <property name="shouldRecover" value="true"/>        <property name="concurrent" value="false"/>        <property name="targetService" value="prodUpdownServiceSchedule"/>        <property name="targetMethod" value="updateProdUpdown"/>     </bean>


在这里配置了一系列参数,在类中有一个静态的子类继承了Job,真正触发的是它,让我们来看一下它的逻辑.

主要注意的是,该类必须要继承FactoryBean, BeanNameAware, InitializingBean三个接口.

FactoryBean接口的作用, 

通过applicationContext获取的对象不是该bean,而是getObject()对象返回的值.所以在service中通过

context_.getBean(className);获取到得是JobDetail.

BeanNameAware的作用:

如果某个 bean 需要访问配置文件中本身的 id 属性,则可以使用 BeanNameAware 接口,

该接口提供了回调本身的能力。实现该接口的 bean,能访问到本身的 id 属性。

InitializingBean的作用:

在Bean被初始化后调用afterPropertiesSet 方法,在该方法中,我们需要进行jobDetail的详细配置.

大致包括如下:

jobDetail = new JobDetail();jobDetail.setName(beanName);jobDetail.setGroup(group);jobDetail.setJobClass(concurrent ? MethodInvokingJob.class : StatefulMethodInvokingJob.class);jobDetail.setDurability(durable);jobDetail.setVolatility(volatility);jobDetail.setRequestsRecovery(shouldRecover);if (targetClass != null)jobDetail.getJobDataMap().put("targetClass", targetClass);if (targetService != null)jobDetail.getJobDataMap().put("targetService", targetService);if (targetObject != null)jobDetail.getJobDataMap().put("targetObject", targetObject);if (targetMethod != null)jobDetail.getJobDataMap().put("targetMethod", targetMethod);if (staticMethod != null)jobDetail.getJobDataMap().put("staticMethod", staticMethod);if (arguments != null)jobDetail.getJobDataMap().put("arguments", arguments);logger.debug("Registering JobListener names with JobDetail object " + beanName);if (this.jobListenerNames != null) {for (int i = 0; i < this.jobListenerNames.length; i++) {this.jobDetail.addJobListener(this.jobListenerNames[i]);}}

静态类,继承Job,后会有一个execute的方法.

public void execute(JobExecutionContext context) throws JobExecutionException {String targetClass = context.getMergedJobDataMap().getString("targetClass");Class targetClassClass = null;if (targetClass != null) {targetClassClass = Class.forName(targetClass); // Could// throw// ClassNotFoundException}Object targetObject = context.getMergedJobDataMap().get("targetObject");String targetService = context.getMergedJobDataMap().getString("targetService");String targetMethod = context.getMergedJobDataMap().getString("targetMethod");String staticMethod = context.getMergedJobDataMap().getString("staticMethod");Object[] arguments = (Object[]) context.getMergedJobDataMap().get("arguments");//方法调用, 通过放射. 目标类,目标对象,目标方法,目标参数,准备,执行MethodInvoker methodInvoker = new MethodInvoker();methodInvoker.setTargetClass(targetClassClass);if (targetObject == null) {targetObject = WebUtils.getBean(targetService);}methodInvoker.setTargetObject(targetObject);methodInvoker.setTargetMethod(targetMethod);methodInvoker.setStaticMethod(staticMethod);methodInvoker.setArguments(arguments);methodInvoker.prepare();methodInvoker.invoke();}

具体API可以查看Spring2.5API