SpringBoot學習(九)--SpringBoot定時任務@Scheduled和動態定時任務
簡介
定時任務或者說定時排程,是系統中比較普遍的一個功能,例如資料歸檔、清理,資料定時同步(非實時),定時收發,流量控制等等都需要用到定時任務,常見的定時排程框架有Quartz、TBSchedule等。
同樣,Spring自3.0版本起也增加了任務排程功能Schedule,它好比是一個輕量級的Quartz,使用起來方便、簡潔,且不需要依賴其他的JAR包。之所以說它是輕量級Quartz,是因為在現如今遍地分散式的大環境下,Spring自帶的Schedule不支援分散式部署,所以若是分散式環境開發請忽略此文章,可以選用Quartz、TBSchedule等,且一般稍大點的公司都有獨立的統一排程中心。
正文
Schedule寫在core包當中,在SpringBoot中使用定時任務只需要簡單配置。
1.首先在**Application啟動類中加入@EnableScheduling註解開啟定時任務。
@SpringBootApplication
//這裡開啟定時任務
@EnableScheduling
public class CmsApplication {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}
2.編寫具體的定時任務元件(@Component註解),並且在需要定時排程的方法上新增@Scheduled觸發器。Spring實現了Quartz簡單的和cron表示式兩種觸發方式,這裡我們用cron表示式,”0/20 * * * * ?”表示每20秒觸發一次,具體cron表示式邏輯可以自行百度。
@Component
public class MyStaticTask {
/**
* 固定cron配置定時任務
*/
@Scheduled(cron = "0/20 * * * * ?")
public void doTask(){
System.out.println("執行了MyStaticTask,時間為:" +new Date(System.currentTimeMillis()));
}
}
以上,一個簡單的定時任務便已完成,但是觸發器是硬編碼,相信肯定滿足不了絕大部分業務場景,同樣Spring提供了SchedulingConfigurer介面,下面介紹可配置、動態修改觸發器的定時任務。
可配置的定時任務元件需要實現SchedulingConfigurer介面中的configureTasks方法,該方法有兩個入參(Runnable task, Trigger trigger),第一個為我們任務的具體邏輯實現,第二個為觸發器,動態的定時任務則意味著Trigger需要動態獲取,由於之前我們已經整合redis,因此這裡我們從redis獲取相關配置。
@Component
public class MyDynamicTask implements SchedulingConfigurer {
private static Logger log = LoggerFactory.getLogger(MyDynamicTask.class);
@Autowired
RedisManager redisManager;
private static String cron;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(doTask(), getTrigger());
}
private Runnable doTask() {
return new Runnable() {
@Override
public void run() {
// 業務邏輯
log.info("執行了MyDynamicTask,時間為:" + new Date(System.currentTimeMillis()));
}
};
}
private Trigger getTrigger() {
return new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// 觸發器
CronTrigger trigger = new CronTrigger(getCron());
return trigger.nextExecutionTime(triggerContext);
}
};
}
public String getCron() {
String newCron = redisManager.getStr("cms:MyDynamicTask");
if (StringUtils.isEmpty(newCron)) {
throw new CmsException("The config cron expression is empty");
}
if (!newCron.equals(cron)) {
log.info(new StringBuffer("Cron has been changed to:'").append(newCron).append("'. Old cron was:'").append(cron).append("'").toString());
cron = newCron;
}
return cron;
}
}
上述cron也可以從其他地方動態獲取,這樣在配置值修改後,定時任務排程器便被更新了,不過需要注意的是,此種方式修改了配置值後,需要在下一次排程結束後,才會更新排程器,並不會在修改配置值時實時更新,實時更新需要在修改配置值時額外增加相關邏輯處理。