Spring4.x整合Quartz2.x动态修改定时器时间(修正多定时器SpringBean异常)

不久前在工作中遇到动态修改定时器的问题,在网上找了一些例子,大部分的写法都差不多,看完过后应用到我的项目中,当时解决了这个问题。但随后我发现这样一个问题:如果再添加一个定时器,在项目启动的时候就会出现SpringBean初始化异常。下面来分析如何解决这个问题:

先来看一下我在百度上看到的此类问题的解决方案, 先修改定时器配置,修改如下:

<bean id="scheduledJob" class="com.web.app.schedule.handlers.CustomScheduledJob">
    <property name="schedulerFactory" ref="scheduledJobFactory"/>
    <property name="triggerKey" ref="scheduledTrigger"/>
</bean>

<bean id="scheduledJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="scheduledJob"/>
    <property name="targetMethod" value="doScheduledJob"/>
    <property name="concurrent" value="false"/>
</bean>

<bean id="scheduledTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="scheduledJobDetail"/>
    <property name="cronExpression">
        <value>*/10 * * * * ?</value>
    </property>
</bean>

<!-- Add scheduled job to project -->
<bean id="scheduledJobFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="scheduledTrigger"/>
        </list>
    </property>
</bean>

CustomScheduledJob类中注入schedulerFactorytriggerKey,那么就可以在这个类中修改定时器的时间了。
然而添加多个定时器任务后,随之而来是的项目启动时,SpringBean装载时异常:
org.springframework.beans.factory.BeanCreationException:…Cannot resolve reference to bean ‘scheduledJobFactory’ while setting bean property ‘schedulerFactory’…
不难看出这是在创建定时器时需要scheduledJobFactory,而scheduledJobFactory的triggers的list里有多个触发器,这些触发器都需要实例化,由此出现了嵌套,导致了创建Bean的异常发生,那该如何修正呢?

既然是创建时的嵌套导致的,那我们就要解除嵌套,即在初始化定时器时不要立即传入scheduledJobFactory的Bean,那么把定时器的配置中的ref改成value,如下:

<bean id="scheduledJob" class="com.web.app.schedule.handlers.CustomScheduledJob">
    <property name="schedulerFactory" value="scheduledJobFactory"/>
    <property name="triggerKey" value="scheduledTrigger"/>
</bean>

那么问题又来了,我们该如何通过value取得Spring的Bean呢?
我们可以通过实现接口ApplicationContextAware方式,重写setApplicationContext()的方法,即可取得Spring的Context,然后用getBean()就可以取得Spring容器里的Bean了。
为了把这个问题处理得更漂亮些,可以用一个抽象类去做这些事情,把其中需要的实现的定时任务方法写成抽象方法,每个定时器去继承此抽象类就可以了,抽象类的写法如下:

package com.web.app.schedule;

import java.text.ParseException;

import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

public abstract class AbstractScheduledJob implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    protected String schedulerFactory;

    protected String triggerKey;

    @Override
    public void setApplicationContext(ApplicationContext appCtx) throws BeansException {
        applicationContext = appCtx;
    }

    public void setSchedulerFactory(String schedulerFactory) {
        Assert.notNull(schedulerFactory, "Scheduler factory can not be null");
        this.schedulerFactory = schedulerFactory;
    }

    public void setTriggerKey(String triggerKey) {
        Assert.notNull(triggerKey, "Trigger key can not be null");
        this.triggerKey = triggerKey;
    }

    public void resetScheduledJob(String cronExpression) throws SchedulerException, ParseException {
        Scheduler schedulerFactory = (Scheduler) getObject(this.schedulerFactory);
        CronTriggerImpl cronTrigger = (CronTriggerImpl) getObject(this.triggerKey);
        String originCronExpression = cronTrigger.getCronExpression();

        if (!originCronExpression.equalsIgnoreCase(cronExpression)) {
            cronTrigger.setCronExpression(cronExpression);
            schedulerFactory.rescheduleJob(cronTrigger.getKey(), cronTrigger);
        }
    }

    public abstract void doScheduledJob();

    protected Object getObject(String name) {
        return applicationContext.getBean(name);
    }

}

自定义的定时器里实现需要处理的计划任务逻辑,写法如下:

package com.web.app.schedule.handlers;

import com.web.app.schedule.AbstractScheduledJob;

public class CustomScheduledJob extends AbstractScheduledJob {

    @Override
    public void doScheduledJob() {
        // TODO
        // 需要处理的计划任务逻辑
    }

}

至此,我们的问题得以解决!

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值