上一節(jié),我們通過(guò)自己?jiǎn)?dòng)一個(gè)線程來(lái)執(zhí)行定時(shí)任務(wù),其實(shí)我們還有許多方便執(zhí)行定時(shí)任務(wù)的方法。quartz是非常出名的一個(gè)定時(shí)任務(wù)框架,spring也提供了一個(gè)定時(shí)任務(wù)框架,兩者使用方法基本一樣,但是spring的定時(shí)任務(wù)框架其實(shí)是quartz的簡(jiǎn)化版,他不支持任務(wù)的持久化,不支持分布式。這里,我們簡(jiǎn)單介紹怎么啟用spring的定時(shí)任務(wù)框架。
1、開(kāi)啟注解

使用@EnableScheduling來(lái)開(kāi)啟注解。
2、Fixed
我們注釋掉之前CmsController里面的”定時(shí)任務(wù)“

新建一個(gè)CmsTimer類

使用@Scheduled注解方法,fixedRate表示每隔多少毫秒執(zhí)行一次。我們還可以通過(guò)設(shè)置initialDelay來(lái)控制第一次執(zhí)行的時(shí)間,如沒(méi)設(shè)置initialDelay的時(shí)候,初始化完就會(huì)馬上執(zhí)行一次,如果我們想1分鐘后再執(zhí)行第一次任務(wù),就可以設(shè)置initialDelay=60*1000。fixedDelay與fixedRate的區(qū)別是,前者是在任務(wù)執(zhí)行完后延遲多久,后者是在任務(wù)開(kāi)始后延遲多久。
3、cron表達(dá)式
@Scheduled(cron = "0 * * * * ?")
上面的cron表達(dá)式,表示每分鐘執(zhí)行一次,第一次執(zhí)行是秒鐘置0的時(shí)候。cron表達(dá)式具體的用法大家自行查找。
4、多任務(wù)
如果我們代碼中定義了多個(gè)定時(shí)任務(wù),恰好幾個(gè)任務(wù)會(huì)同時(shí)執(zhí)行,會(huì)發(fā)現(xiàn)任務(wù)會(huì)有延遲或丟失的可能,這是因?yàn)?,spring提供的定時(shí)任務(wù)其實(shí)底層就是ScheduledThreadPoolExecutor,默認(rèn)只有一個(gè)任務(wù)線程,一個(gè)線程執(zhí)行完當(dāng)前任務(wù),才能執(zhí)行另外一個(gè)任務(wù)。如果碰到任務(wù)執(zhí)行不過(guò)來(lái)的情況,我們可以加大線程池,通過(guò)spring.task.scheduling.pool.size配置。

我們還可以配置異步線程,spring將默認(rèn)開(kāi)啟8個(gè)線程來(lái)執(zhí)行異步操作。
5、總結(jié)
這節(jié)我們講了怎么在spring里面快速實(shí)現(xiàn)定時(shí)任務(wù),文章開(kāi)頭我們說(shuō)了,這種方式不支持任務(wù)持久化,不支持分布式,如果需要這兩個(gè)特性,我們可以使用quartz,或者自己在spring定時(shí)任務(wù)上做一點(diǎn)點(diǎn)開(kāi)發(fā)工作。例如,如果要支持集群部署,有時(shí)我們可以在配置文件里面增加一個(gè)變量,配置是否開(kāi)啟定時(shí)任務(wù),這樣就會(huì)只有一臺(tái)機(jī)器跑定時(shí)任務(wù),這也是我們常見(jiàn)的做法。如果要真正的分布式,我們也可以通過(guò)redis加鎖,或者zookeeper的方式實(shí)現(xiàn)。
代碼:
https://github.com/www15119258/springboot-study/tree/branch35