spring boot @Scheduled未生效原因以及相關坑、及相對其他定時任務架構的優勢


在spring boot中,支持多種定時執行模式(cron, fixRate, fixDelay),在Application或者其他Autoconfig上增加@EnableScheduling注解開啟。

然后在指定方法增加@Scheduled注解,如下:

    @Scheduled(cron="0 0 0/1 * * ?")
    public void updateTime() {
        current_log_time_appendix = sdf.format(new Date());
        logger.info("日志文件切換, 切換后為:" + current_log_time_appendix);
    }

 需要注意的是,如果在多個函數上使用了@Scheduled,那么一定是一個執行完畢,才能排下一個。這往往不是我們想要的效果。此時需要在Scheduling配置類為schedule返回一個預定的線程池,如下:

@Configuration
@EnableScheduling
public class SchedulingConfiguration {
    @Bean(destroyMethod = "shutdown")
    public Executor taskScheduler() {
        return Executors.newScheduledThreadPool(10);
    }
}

完成之后,多個@Scheduled可以並發執行了,最高並發度是3,但是同一個@Schedule不會並發執行。

除了cron表達式和quartz、es-job以及linux cron等一樣靈活外, spring容器托管的定時任務方法能夠利用現成的依賴注入體系,例如:

    @Scheduled(cron="0 * * * * *") // 表達式也可以通過@Value注入,例如@Scheduled(cron = "${cron_expression}")
    public void ss() {
        XXXParameter<BaseParameter> param = new TaLiquidateParameter<>();
        param.setTenantCode("*");
        param.setLongTaCode("F6");
        param.setDatabaseNo("1");
        BaseParameter data = new BaseParameter();
        data.setLiqBatchNo("1");
        data.setIoFlow("EXPORTCONDATA");
        param.setData(data);
        interfaceDataPrepare(param );  // 當前bean的方法,會依賴其它bean
    }

其它的方式就必須通過ApplicationContext取主動lookup的方式獲取了。但是它的缺點是不支持集群,此時仍然需要其它控制機制,所以用來做測試或者其它不需要集群的場景是不錯的。

各種cron表達式備忘如下:

0 * * * * *:每分鍾(當秒為0的時候)
0 0 * * * *:每小時(當秒和分都為0的時候)
*/10 * * * * *:每10秒
0 5/15 * * * *:每小時的5分、20分、35分、50分
0 0 9,13 * * *:每天的9點和13點
0 0 8-10 * * *:每天的8點、9點、10點
0 0/30 8-10 * * *:每天的8點、8點半、9點、9點半、10點
0 0 9-17 * * MON-FRI:每周一到周五的9點、10點…直到17點(含)
0 0 0 25 12 ?:每年12約25日聖誕節的0點0分0秒(午夜)
0 30 10 * * ? 2016:2016年每天的10點半

其中的?在用法上其實和*是相同的。但是*語義上表示全匹配,而?並不代表全匹配,而是不關心。比如對於0 0 0 5 8 ? 2016來說,2016年8月5日是周五,?表示我不關心它是周幾。而0 0 0 5 8 * 2016中的*表示周一也行,周二也行……語義上和2016年8月5日沖突了,你說誰優先生效呢。

不記得也沒關系,記住Cron Maker也可以,它可以在線生成cron表達式。

 

同時運行

同一個task,如果前一個還沒跑完后面一個就不會觸發,這沒有問題。但是不同的task也不能同時運行就不太合理了。不過其實是scheduler的默認線程數為1的緣故。

解決方法1:如下配置pool-size,但這樣會導致同一個task前一個還沒跑完后面又被觸發的問題。

<task:scheduler id="scheduler" pool-size="2" />

解決方法2:讓任務分別運行在不同的scheduler里。例如:

<task:scheduler id="myScheduler1"/>
<task:scheduler id="myScheduler2"/>
<task:scheduled-tasks scheduler="myScheduler1">
    <task:scheduled ref="doSomethingTask" method="doSomething" cron="${0 * * * * *}"/>
</task:scheduled-tasks>
<task:scheduled-tasks scheduler="myScheduler2">
    <task:scheduled ref="doOtherThingTask" method="doOtherThing" cron="${0 * * * * *}"/>
</task:scheduled-tasks>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM