程式碼控制Quartz的啟動和停止
阿新 • • 發佈:2018-12-06
Spring中如何使用Quartz就不必說了,這裡說說如果動態設定cron。
這個要解決3個問題:
1.將使用者輸入轉換為Cron表示式
2.安全的重啟quartz
3.程式啟動的時候,從資料庫中讀取cron(而非spring配置檔案中寫死的那個)。
因為derpvail急著用,所以先說第3個。
動態讀取資料庫中的Cron,作為CronTriggerBean的屬性
從資料庫中讀取cron,需要做一個CronExpressionFactoryBean,它是一個Spring的FactoryBean,可以讀取資料庫,並建立一個CronExpression物件:
然後呢,就是吧這個CronExpression物件注入到CronTriggerBean,但是CronTriggerBean的setCronExpression方法是過載的,本人不知道如何注入過載方法,所以只好繼承了CronTriggerBean,添加了一個setCron方法,一遍於Spring的注入:
然後就是在spring中配置這兩個Bean了,和普通的quartz類似,只不過cronExpression屬性改為了cron屬性:
這個要解決3個問題:
1.將使用者輸入轉換為Cron表示式
2.安全的重啟quartz
3.程式啟動的時候,從資料庫中讀取cron(而非spring配置檔案中寫死的那個)。
因為derpvail急著用,所以先說第3個。
動態讀取資料庫中的Cron,作為CronTriggerBean的屬性
從資料庫中讀取cron,需要做一個CronExpressionFactoryBean,它是一個Spring的FactoryBean,可以讀取資料庫,並建立一個CronExpression物件:
public class CronFactoryBean implements FactoryBean { private static Logger logger = LoggerFactory.getLogger(CronFactoryBean.class); @Autowired @Qualifier("defaultFreq") private String defaultCron; /** * 用於取得CRON表示式. */ @Autowired(required = true) private CronManager cronManager; /** * 從資料庫中取得CRON表示式,如果資料庫中沒有則取預設值. * @see EmailConstants#DEFALUT_CRON */ @Override public Object getObject() throws Exception { //如何讀取資料庫,就省了 String cronEx = cronManager.getCronExpression(); if(StringUtils.isBlank(cronEx)) { return new CronExpression(defaultCron); } return new CronExpression(cronEx.trim()); } @SuppressWarnings("unchecked") @Override public Class getObjectType() { return CronExpression.class; } @Override public boolean isSingleton() { return true; } }
然後呢,就是吧這個CronExpression物件注入到CronTriggerBean,但是CronTriggerBean的setCronExpression方法是過載的,本人不知道如何注入過載方法,所以只好繼承了CronTriggerBean,添加了一個setCron方法,一遍於Spring的注入:
/** * FIXME:因為目前不知道如何實現過載方法的注入,而<code>CronTrigger</code> * 的<code>setCronExpression</code>既可以用<code>CronExpression</code> * 物件作為引數也可以用String作為引數,這就產生了不確定性。所以,我們extends了 * <code>CronTriggerBean</code>,提供{@link #setCron(CronExpression)} * 方法,避免這種不確定性。 * @author Sam * */ public class CronTriggerBeanEx extends CronTriggerBean { /** * 呼叫父類的{@link CronTriggerBean#setCronExpression(CronExpression)} * 方法. */ public void setCron(CronExpression cronExpression) { this.setCronExpression(cronExpression); } }
然後就是在spring中配置這兩個Bean了,和普通的quartz類似,只不過cronExpression屬性改為了cron屬性:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans default-lazy-init="false"> <bean id="seismicEmailCronTrigger" class="datashare.email.admin.jobs.CronTriggerBeanEx"> <property name="jobDetail" ref="seismicEmailJobDetail" /> <property name="cron"> <bean class="datashare.email.admin.jobs.CronFactoryBean"> </property> </bean> </property> </bean> </beans>
注意default-lazy-init="false",這樣,quartz就可以在專案啟動的時候,讀取資料庫中的cron了。
安全的重啟quartz
貌似網上的文章都不太對,下面的這方法可以正常執行,在此之前,你應該把ApplicationContext注入,可以用ApplicationContextAware介面,也可以用@Autowired註解:
@Autowired(required = true)
private ApplicationContext ctx;
/**
* 如果cron改變,則重新啟動Quartz任務。
* @param signCron 使用者輸入的CRON,你可以把它先存入資料庫
* @throws ApplicationException 如果CRON無法解析,或原來的任務無法關閉,以及無法啟動新任務.
*/
private void restartJobs(String signCron) {
if(StringUtils.isBlank(signCron)) {
logger.warn("CRON未設定。");
return;
}
//trim一下,難保沒有空格
signCron = signCron.trim();
//得到trigger
CronTrigger signCronTrigger = (CronTrigger) ctx.getBean("signEmailCronTrigger", CronTrigger.class);
//如果頻率都有變,則不必重新啟動.
if(signCron.equals(signCronTrigger.getCronExpression())) {
logger.info("前兆和測震傳送頻率都未改變,Quartz不必重新啟動.");
return;
}
//[b]下面是關鍵[/b]
//得到SchedulerFactoryBean的例項,注意beanName前面的&符號
SchedulerFactoryBean schedulerFactory = (SchedulerFactoryBean) ctx.getBean("&emailSchedulerFactory");
try {
//重新設定trigger
signCronTrigger.setCronExpression(signCron);
schedulerFactory.destroy(); //關閉原來的任務
schedulerFactory.afterPropertiesSet(); //啟動新的任務
logger.info("XXX任務啟動成功.");
} catch (ParseException e) {
throw new ApplicationException("Cron表示式解析錯誤." + e.getMessage());
} catch (SchedulerException e) {
e.printStackTrace();
throw new ApplicationException("關閉定時任務出現異常.");
} catch (Exception e) {
e.printStackTrace();
throw new ApplicationException("啟動定時任務出現異常.");
}
}
//我原來的程式碼和這個略有不同,這段程式碼沒有除錯過(在JE上編輯的),不過應該可以執行
文章轉載 http://cats-tiger.iteye.com/blog/440687