1. 程式人生 > >SpringBoot學習(九)--SpringBoot定時任務@Scheduled和動態定時任務

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也可以從其他地方動態獲取,這樣在配置值修改後,定時任務排程器便被更新了,不過需要注意的是,此種方式修改了配置值後,需要在下一次排程結束後,才會更新排程器,並不會在修改配置值時實時更新,實時更新需要在修改配置值時額外增加相關邏輯處理。