不久前在工作中遇到动态修改定时器的问题,在网上找了一些例子,大部分的写法都差不多,看完过后应用到我的项目中,当时解决了这个问题。但随后我发现这样一个问题:如果再添加一个定时器,在项目启动的时候就会出现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>12345678910111213141516171819202122232425261234567891011121314151617181920212223242526在CustomScheduledJob类中注入schedulerFactory和triggerKey,那么就可以在这个类中修改定时器的时间了。 然而添加多个定时器任务后,随之而来是的项目启动时,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>12341234那么问题又来了,我们该如何通过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); }}1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253自定义的定时器里实现需要处理的计划任务逻辑,写法如下:
package com.web.app.schedule.handlers;import com.web.app.schedule.AbstractScheduledJob;public class CustomScheduledJob extends AbstractScheduledJob { @Override public void doScheduledJob() { // TODO // 需要处理的计划任务逻辑 }}1234567891011121312345678910111213至此,我们的问题得以解决!
新闻热点
疑难解答