scheduled只执行一次_升级@Scheduled-分布式定时任务
最近我在對(duì)項(xiàng)目的定時(shí)任務(wù)服務(wù)升級(jí),希望改造成分布式,原本是利用@Scheduled注解實(shí)現(xiàn),然而它并不支持分布式,如果改成quartz或者Spring Cloud Task,感覺(jué)對(duì)于自己這個(gè)簡(jiǎn)單的項(xiàng)目也沒(méi)有必要。因此,我準(zhǔn)備手寫(xiě)一個(gè)簡(jiǎn)單的支持分布式定時(shí)調(diào)度任務(wù)的框架。
項(xiàng)目地址是https://github.com/death00/dis-schedule,歡迎大家star、提意見(jiàn)。
分析
先分析了一下自己的項(xiàng)目,全都是用的cron表達(dá)式,因此執(zhí)行時(shí)間點(diǎn)都是固定的,如果升級(jí)為分布式的話(huà),肯定是希望在同一個(gè)時(shí)間點(diǎn)只有一個(gè)應(yīng)用去執(zhí)行定時(shí)調(diào)度。
場(chǎng)景就變成了:
多個(gè)應(yīng)用在同一個(gè)時(shí)間都嘗試去執(zhí)行任務(wù),但最終只有一個(gè)應(yīng)用真正執(zhí)行。這樣的話(huà),立馬就會(huì)讓人聯(lián)想到使用鎖去解決,因?yàn)槭嵌鄠€(gè)應(yīng)用,所以就是分布式鎖。那么,場(chǎng)景又變了:
多個(gè)應(yīng)用在同一個(gè)時(shí)間都嘗試去獲取分布式鎖,只有一個(gè)應(yīng)用能搶到這把鎖,搶到鎖的應(yīng)用可以執(zhí)行定時(shí)任務(wù),其他應(yīng)用則直接放棄,等待下一次執(zhí)行時(shí)間。搶鎖的時(shí)機(jī)是每次定時(shí)任務(wù)執(zhí)行之前,這又讓我聯(lián)想到了AOP,那么利用注解也就順理成章了。
分布式鎖
既然談到了分布式鎖,那么就想一下,這把鎖的名稱(chēng)構(gòu)成是什么。因?yàn)槎〞r(shí)任務(wù)都有自己專(zhuān)門(mén)的時(shí)間,如果僅僅采用時(shí)間的話(huà),那么當(dāng)有兩個(gè)任務(wù)同時(shí)執(zhí)行時(shí),則就是在搶一把鎖,這同樣是不合理的。
所以,鎖的名稱(chēng)由兩部分組成:任務(wù)執(zhí)行時(shí)間、任務(wù)名稱(chēng)。
實(shí)現(xiàn)
實(shí)現(xiàn)方案其實(shí)已經(jīng)很成熟了,可以利用Redis、數(shù)據(jù)庫(kù)、Zookeeper等,Redis用的命令是setNx,數(shù)據(jù)庫(kù)一般都是利用的唯一索引,Zookeeper這點(diǎn)我也不是很了解(如果有感興趣的同學(xué),歡迎在我的項(xiàng)目中添加)。
我的項(xiàng)目中實(shí)現(xiàn)了Redis、數(shù)據(jù)庫(kù)兩種方式,可以看類(lèi)DisScheduleRedisServiceImpl、DisScheduleMongodbServiceImpl。
注解
其次,我自定義了一個(gè)注解DisSchedule,
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface DisSchedule {/*** 定時(shí)調(diào)度任務(wù)的名稱(chēng)(默認(rèn)是方法名)*/String name() default "";/*** 任務(wù)的間隔時(shí)間*/int duration();/*** duration的時(shí)間單位(默認(rèn):分鐘)*/DisScheduleUnit unit() default DisScheduleUnit.MINUTES; }該注解需要配合@Scheduled共同使用,例如:
@DisSchedule(name = "testSchedule", duration = 1, unit = DisScheduleUnit.MINUTES)@Scheduled(cron = "0 0/1 * * * ?")該cron表達(dá)式代表1分鐘執(zhí)行一次,且是在整數(shù)分鐘開(kāi)始的時(shí)候執(zhí)行,因此@DisSchedule也需要設(shè)置為1分鐘的時(shí)間。
切面
接下來(lái),我們只需要在Aspect中定義好切入點(diǎn)(有注解@DisSchedule的方法上),針對(duì)這些方法,需要使用Around(環(huán)繞增強(qiáng))進(jìn)行攔截,因?yàn)楫?dāng)搶不到鎖的時(shí)候,就不允許執(zhí)行。
具體可以參考類(lèi)DisScheduleAspect。
總結(jié)
以上就是我實(shí)現(xiàn)的簡(jiǎn)單的分布式定時(shí)任務(wù),雖然簡(jiǎn)單,但應(yīng)該可以滿(mǎn)足你的基礎(chǔ)需求,接下來(lái),我會(huì)在這個(gè)之上,逐步增加功能(比如監(jiān)測(cè)、失敗后預(yù)警等)。如果你有什么想法,歡迎在下方留言。
有興趣的話(huà)可以訪問(wèn)我的博客或者關(guān)注我的公眾號(hào)、頭條號(hào),說(shuō)不定會(huì)有意外的驚喜。
https://death00.github.io/
總結(jié)
以上是生活随笔為你收集整理的scheduled只执行一次_升级@Scheduled-分布式定时任务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vivoy93像素是多少
- 下一篇: java xml解析_XML的理解以及S