精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

動態更改 Spring 定時任務 Cron 表達式的優雅方案!

開發 前端
我們在上文通過定時刷新和重建任務的方式來實現了動態更改Cron表達式的需求,能夠滿足大部分的項目場景,而且沒有引入quartzs等額外的中間件,可以說是十分的輕量和優雅了。

在 SpringBoot 項目中,我們可以通過@EnableScheduling注解開啟調度任務支持,并通過@Scheduled注解快速地建立一系列定時任務。

@Scheduled支持下面三種配置執行時間的方式:

  • cron(expression):根據Cron表達式來執行。
  • fixedDelay(period):固定間隔時間執行,無論任務執行長短,兩次任務執行的間隔總是相同的。
  • fixedRate(period):固定頻率執行,從任務啟動之后,總是在固定的時刻執行,如果因為執行時間過長,造成錯過某個時刻的執行(晚點),則任務會被立刻執行。

最常用的應該是第一種方式,基于Cron表達式的執行模式,因其相對來說更加靈活。

可變與不可變

默認情況下,@Scheduled注解標記的定時任務方法在初始化之后,是不會再發生變化的。Spring 在初始化 bean 后,通過后處理器攔截所有帶有@Scheduled注解的方法,并解析相應的的注解參數,關注公眾號:碼猿技術專欄,回復關鍵詞:1111 獲取阿里內部Java性能調優手冊!放入相應的定時任務列表等待后續統一執行處理。到定時任務真正啟動之前,我們都有機會更改任務的執行周期等參數。

換言之,我們既可以通過application.properties配置文件配合@Value注解的方式指定任務的Cron表達式,亦可以通過CronTrigger從數據庫或者其他任意存儲中間件中加載并注冊定時任務。這是 Spring 提供給我們的可變的部分。

但是我們往往要得更多。能否在定時任務已經在執行過的情況下,去動態更改Cron表達式,甚至禁用某個定時任務呢?很遺憾,默認情況下,這是做不到的,任務一旦被注冊和執行,用于注冊的參數便被固定下來,這是不可變的部分。

創造與毀滅

既然創造之后不可變,那就毀滅之后再重建吧。于是乎,我們的思路便是,在注冊期間保留任務的關鍵信息,并通過另一個定時任務檢查配置是否發生變化,如果有變化,就把“前任”干掉,取而代之。如果沒有變化,就保持原樣。

先對任務做個簡單的抽象,方便統一的識別和管理:

public interface IPollableService {
    /**
     * 執行方法
     */
    void poll();

    /**
     * 獲取周期表達式
     *
     * @return CronExpression
     */
    default String getCronExpression() {
        returnnull;
    }

    /**
     * 獲取任務名稱
     *
     * @return 任務名稱
     */
    default String getTaskName() {
        returnthis.getClass().getSimpleName();
    }
}

最重要的便是getCronExpression()方法,每個定時服務實現可以自己控制自己的表達式,變與不變,自己說了算。至于從何處獲取,怎么獲取,請諸君自行發揮了。接下來,就是實現任務的動態注冊:

@Configuration
@EnableAsync
@EnableScheduling
publicclass SchedulingConfiguration implements SchedulingConfigurer, ApplicationContextAware {
    privatestaticfinal Logger log = LoggerFactory.getLogger(SchedulingConfiguration.class);
    privatestatic ApplicationContext appCtx;
    privatefinal ConcurrentMap<String, ScheduledTask> scheduledTaskHolder = new ConcurrentHashMap<>(16);
    privatefinal ConcurrentMap<String, String> cronExpressionHolder = new ConcurrentHashMap<>(16);
    private ScheduledTaskRegistrar taskRegistrar;

    public static synchronized void setAppCtx(ApplicationContext appCtx) {
        SchedulingConfiguration.appCtx = appCtx;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        setAppCtx(applicationContext);
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        this.taskRegistrar = taskRegistrar;
    }

    /**
     * 刷新定時任務表達式
     */
    public void refresh() {
        Map<String, IPollableService> beanMap = appCtx.getBeansOfType(IPollableService.class);
        if (beanMap.isEmpty() || taskRegistrar == null) {
            return;
        }
        beanMap.forEach((beanName, task) -> {
            String expression = task.getCronExpression();
            String taskName = task.getTaskName();
            if (null == expression) {
                log.warn("定時任務[{}]的任務表達式未配置或配置錯誤,請檢查配置", taskName);
                return;
            }
            // 如果策略執行時間發生了變化,則取消當前策略的任務,并重新注冊任務
            boolean unmodified = scheduledTaskHolder.containsKey(beanName) && cronExpressionHolder.get(beanName).equals(expression);
            if (unmodified) {
                log.info("定時任務[{}]的任務表達式未發生變化,無需刷新", taskName);
                return;
            }
            Optional.ofNullable(scheduledTaskHolder.remove(beanName)).ifPresent(existTask -> {
                existTask.cancel();
                cronExpressionHolder.remove(beanName);
            });
            if (ScheduledTaskRegistrar.CRON_DISABLED.equals(expression)) {
                log.warn("定時任務[{}]的任務表達式配置為禁用,將被不會被調度執行", taskName);
                return;
            }
            CronTask cronTask = new CronTask(task::poll, expression);
            ScheduledTask scheduledTask = taskRegistrar.scheduleCronTask(cronTask);
            if (scheduledTask != null) {
                log.info("定時任務[{}]已加載,當前任務表達式為[{}]", taskName, expression);
                scheduledTaskHolder.put(beanName, scheduledTask);
                cronExpressionHolder.put(beanName, expression);
            }
        });
    }
}

重點是保存ScheduledTask對象的引用,它是控制任務啟停的關鍵。而表達式“-”則作為一個特殊的標記,用于禁用某個定時任務。

當然,禁用后的任務通過重新賦予新的 Cron 表達式,是可以“復活”的。完成了上面這些,我們還需要一個定時任務來動態監控和刷新定時任務配置:

@Component
publicclass CronTaskLoader implements ApplicationRunner {
    privatestaticfinal Logger log = LoggerFactory.getLogger(CronTaskLoader.class);
    privatefinal SchedulingConfiguration schedulingConfiguration;
    privatefinal AtomicBoolean appStarted = new AtomicBoolean(false);
    privatefinal AtomicBoolean initializing = new AtomicBoolean(false);

    public CronTaskLoader(SchedulingConfiguration schedulingConfiguration) {
        this.schedulingConfiguration = schedulingConfiguration;
    }

    /**
     * 定時任務配置刷新
     */
    @Scheduled(fixedDelay = 5000)
    public void cronTaskConfigRefresh() {
        if (appStarted.get() && initializing.compareAndSet(false, true)) {
            log.info("定時調度任務動態加載開始>>>>>>");
            try {
                schedulingConfiguration.refresh();
            } finally {
                initializing.set(false);
            }
            log.info("定時調度任務動態加載結束<<<<<<");
        }
    }

    @Override
    public void run(ApplicationArguments args) {
        if (appStarted.compareAndSet(false, true)) {
            cronTaskConfigRefresh();
        }
    }
}

當然,也可以把這部分代碼直接整合到SchedulingConfiguration中,但是為了方便擴展,這里還是將執行與觸發分離了。畢竟除了通過定時任務觸發刷新,還可以在界面上通過按鈕手動觸發刷新,或者通過消息機制回調刷新。這一部分就請大家根據實際業務情況來自由發揮了。

驗證

我們創建一個原型工程和三個簡單的定時任務來驗證下,第一個任務是執行周期固定的任務,假設它的Cron表達式永遠不會發生變化,像這樣:

@Service
public class CronTaskBar implements IPollableService {
    @Override
    public void poll() {
        System.out.println("Say Bar");
    }

    @Override
    public String getCronExpression() {
        return "0/1 * * * * ?";
    }
}

第二個任務是一個經常更換執行周期的任務,我們用一個隨機數發生器來模擬它的善變:

@Service
publicclass CronTaskFoo implements IPollableService {
    privatestaticfinal Random random = new SecureRandom();

    @Override
    public void poll() {
        System.out.println("Say Foo");
    }

    @Override
    public String getCronExpression() {
        return"0/" + (random.nextInt(9) + 1) + " * * * * ?";
    }
}

第三個任務就厲害了,它仿佛就像一個電燈的開關,在啟用和禁用中反復橫跳:

@Service
publicclass CronTaskUnavailable implements IPollableService {
    private String cronExpression = "-";
    privatestaticfinal Map<String, String> map = new HashMap<>();

    static {
        map.put("-", "0/1 * * * * ?");
        map.put("0/1 * * * * ?", "-");
    }

    @Override
    public void poll() {
        System.out.println("Say Unavailable");
    }

    @Override
    public String getCronExpression() {
        return (cronExpression = map.get(cronExpression));
    }
}

如果上面的步驟都做對了,日志里應該能看到類似這樣的輸出:

定時調度任務動態加載開始>>>>>>
定時任務[CronTaskBar]的任務表達式未發生變化,無需刷新
定時任務[CronTaskFoo]已加載,當前任務表達式為[0/6 * * * * ?]
定時任務[CronTaskUnavailable]的任務表達式配置為禁用,將被不會被調度執行
定時調度任務動態加載結束<<<<<<
Say Bar
Say Bar
Say Foo
Say Bar
Say Bar
Say Bar
定時調度任務動態加載開始>>>>>>
定時任務[CronTaskBar]的任務表達式未發生變化,無需刷新
定時任務[CronTaskFoo]已加載,當前任務表達式為[0/3 * * * * ?]
定時任務[CronTaskUnavailable]已加載,當前任務表達式為[0/1 * * * * ?]
定時調度任務動態加載結束<<<<<<
Say Unavailable
Say Bar
Say Unavailable
Say Bar
Say Foo
Say Unavailable
Say Bar
Say Unavailable
Say Bar
Say Unavailable
Say Bar

小結

我們在上文通過定時刷新和重建任務的方式來實現了動態更改Cron表達式的需求,能夠滿足大部分的項目場景,而且沒有引入quartzs等額外的中間件,可以說是十分的輕量和優雅了。當然,如果各位看官有更好的方法,還請不吝賜教。

責任編輯:武曉燕 來源: 碼猿技術專欄
相關推薦

2017-08-16 16:41:04

JavaSpringBoot定時任務

2024-03-13 14:40:35

SpringCron表達式

2024-05-13 09:49:30

.NETQuartz庫Cron表達式

2022-08-15 15:43:29

Linuxcron

2010-01-07 13:38:41

Linux定時任務

2024-02-29 07:28:44

Cron表達式解析庫

2024-02-02 12:41:33

表達式語法Cron

2025-10-09 07:47:04

2012-02-07 13:31:14

SpringJava

2024-06-03 00:00:01

表達式PythonJava

2022-06-07 07:43:44

HealthchecCronPython

2024-07-31 14:03:00

Spring定時任務管理

2022-11-11 14:55:14

Linuxcron

2025-04-27 08:01:25

2021-11-22 12:35:40

Python命令定時任務

2024-01-31 08:38:57

Python定時任務函數

2022-01-14 07:56:39

C#動態查詢

2021-09-26 09:17:01

Python命令定時任務

2024-10-10 10:32:04

2018-10-08 14:00:28

LinuxCron定時任務
點贊
收藏

51CTO技術棧公眾號

亚洲av成人无码一二三在线观看| 日韩欧美国产视频| 美日韩精品免费观看视频| 中文字幕一区二区三区四| 奇米影视888狠狠狠777不卡| 麻豆九一精品爱看视频在线观看免费| 91精品国产品国语在线不卡| 成人福利网站在线观看11| 精品日韩在线视频| 在线视频超级| 国产精品福利一区| 欧美丰满少妇xxxxx| av网站免费在线看| 亚洲综合色婷婷在线观看| 久久久久久久久久久电影| 成人午夜高潮视频| 麻豆精品久久久久久久99蜜桃| 秋霞综合在线视频| 欧美一区二区免费观在线| 免费日韩中文字幕| www.九色在线| 亚洲欧美经典视频| 午夜一区二区三区| 日本成人一区二区三区| 国产福利一区在线| 国产精品亚洲美女av网站| 青青草av在线播放| 欧美日韩综合| 久久亚洲精品毛片| 2019男人天堂| 九九综合在线| 精品中文字幕久久久久久| 巨乳女教师的诱惑| 日韩三级成人| 欧美私模裸体表演在线观看| 国产黄视频在线| 男插女视频久久久| 一区二区激情小说| 国产日韩欧美大片| 黄色网在线看| 17c精品麻豆一区二区免费| 天堂av一区二区| 国内在线免费高清视频| 2020国产成人综合网| 精品视频导航| 亚洲av成人精品毛片| 不卡欧美aaaaa| 国产传媒一区二区| 人妻少妇精品无码专区久久| 国产91在线|亚洲| 999视频在线免费观看| 国产欧美日韩综合精品一区二区三区| 蜜臀av性久久久久av蜜臀妖精| 国产精品福利网站| 真实的国产乱xxxx在线91| 日日夜夜免费精品| 欧美亚洲视频在线看网址| 中国一级特黄毛片| 鲁大师影院一区二区三区| 97婷婷大伊香蕉精品视频| 国产精品黄色大片| 日韩黄色片在线观看| 国产精品久久久久久久久久免费| 精人妻无码一区二区三区| 天堂成人国产精品一区| 国产精品九九久久久久久久| 一级黄色大片免费观看| 国产美女主播视频一区| 亚洲自拍偷拍网址| 高清乱码毛片入口| www国产亚洲精品久久麻豆| 欧美大香线蕉线伊人久久| 国产主播福利在线| 中文字幕一区二区日韩精品绯色| 亚洲黄色网址在线观看| 日本在线视频网址| 精品人伦一区二区三区蜜桃网站| 久久午夜夜伦鲁鲁一区二区| 久久精品97| 日韩欧美电影一区| 国产精品三级在线观看无码| 不卡中文字幕| 久久99精品久久久久久噜噜| 日本网站在线播放| 丝袜国产日韩另类美女| 成人在线播放av| 丰满人妻一区二区三区四区53 | 亚洲高清免费在线| 国产精品秘入口18禁麻豆免会员| 成人在线高清| 精品少妇一区二区三区视频免付费| 中文字幕影片免费在线观看| 日韩午夜电影网| 久久久久久久国产| 最新国产中文字幕| 成人免费毛片a| 天堂一区二区三区| heyzo在线播放| 欧美影视一区在线| 91丝袜在线观看| 久久综合88| 97精品在线观看| 91丨porny丨在线中文| 99久久综合国产精品| 一区二区精品在线观看| 麻豆蜜桃在线观看| 欧美一区二区三区免费| 91成人破解版| 影音先锋一区| 成人黄色在线观看| 经典三级在线| 亚洲sss视频在线视频| 粉色视频免费看| 香蕉久久精品| 欧美激情免费在线| 国产精品综合在线| 国产拍揄自揄精品视频麻豆| 日韩亚洲欧美视频| 国产一区二区三区免费在线| 亚洲天堂视频在线观看| 日韩欧美亚洲一区二区三区| 国产精品伊人色| 亚洲第一在线综合在线| 亚洲风情在线资源| 精品sm捆绑视频| 极品久久久久久| 麻豆国产91在线播放| 欧美性大战久久久久| 免费高潮视频95在线观看网站| 欧美一区二区高清| 久久嫩草捆绑紧缚| 麻豆高清免费国产一区| 亚洲第一在线综合在线| 日本国产欧美| 亚洲区免费影片| 东京热一区二区三区四区| a级高清视频欧美日韩| 亚洲色成人www永久在线观看| 免费精品一区| 欧美超级乱淫片喷水| 国产乱色精品成人免费视频| 一区在线播放视频| 最新天堂在线视频| 国产精品99久久| 91影院在线免费观看视频| 久草资源在线| 91精品视频网| 免费人成在线观看| 丁香桃色午夜亚洲一区二区三区| 日韩精品免费一区| 北条麻妃一区二区三区在线观看| 欧美激情精品久久久久久蜜臀| www.av黄色| 亚洲伊人伊色伊影伊综合网| 中国黄色片视频| 99精品福利视频| 蜜桃视频日韩| 91在线成人| www日韩中文字幕在线看| 国产精品一区二区av白丝下载 | 好吊妞视频一区二区三区| 99国产精品99久久久久久| 久久久免费视频网站| 欧美女王vk| 91精品久久久久久| 三级资源在线| 亚洲国产精久久久久久 | 午夜av在线播放| 亚洲第一精品福利| 91video| 国产一区二区精品久久99| 亚洲 欧美 综合 另类 中字| 台湾色综合娱乐中文网| 国产精品日日摸夜夜添夜夜av| 色影院视频在线| 欧美r级在线观看| 在线观看免费av片| 一色屋精品亚洲香蕉网站| 无码人妻一区二区三区在线| 国产精品综合| 一区二区免费电影| 欧美自拍一区| 国产日韩欧美电影在线观看| 黄网av在线| 一区二区三区视频在线| 精品国产无码AV| 一本大道综合伊人精品热热 | 欧美视频综合| 欧美精品日韩一本| 日韩精品乱码久久久久久| 国产欧美综合色| 91精品国产高清91久久久久久 | 国产精品爱啪在线线免费观看| 免费a在线看| 精品国产一区二区三区不卡| 国产一卡二卡三卡| 亚洲一区在线视频| 91导航在线观看| 美女尤物国产一区| 国产午夜伦鲁鲁| 一区二区三区午夜视频| 热舞福利精品大尺度视频| 亚洲日本视频在线| 久久6免费高清热精品| 国产二区在线播放| 亚洲精品电影久久久| 国产欧美一级片| 欧美午夜精品久久久久久超碰| 精品无码久久久久久久久| 国产精品久久夜| 91成人破解版| 91免费在线视频观看| 免费看91视频| 国产一区二区三区蝌蚪| wwww.国产| 久久久久99| 欧美日韩性生活片| 免费观看不卡av| 精品福利影视| 成人爽a毛片免费啪啪红桃视频| 91精品国产综合久久香蕉最新版 | 五月久久久综合一区二区小说| 久久青青草原一区二区| 国产一区丝袜| 999国内精品视频在线| 精品999日本久久久影院| 国产欧美欧洲在线观看| 欧美日韩五码| 欧洲亚洲女同hd| 三级在线看中文字幕完整版| 欧美精品在线观看| 成人片在线看| 久久av资源网站| 国产精品国产高清国产| 精品国产不卡一区二区三区| 精品乱子伦一区二区| 91精品国产91久久综合桃花| 国产一区二区小视频| 欧美亚洲一区二区在线观看| 五月婷婷丁香在线| 在线一区二区三区| 青娱乐在线免费视频| 欧美性欧美巨大黑白大战| 中文字幕av影视| 欧美日韩国产综合草草| 11024精品一区二区三区日韩| 欧美伊人久久久久久午夜久久久久| 午夜精品免费观看| 91福利在线看| 日批视频免费观看| 欧美日韩国产系列| 99精品免费观看| 欧美不卡激情三级在线观看| 黄色小视频免费观看| 亚洲精品99999| 九九九伊在人线综合| 中文字幕日韩视频| 黄色精品免费看| 久久久久久国产精品久久| 精品丝袜在线| 国产精品黄色影片导航在线观看| 成人精品高清在线视频| 91久久精品国产91久久| 99久久香蕉| 九色视频成人porny| 国产一区二区在线| 综合视频免费看| 精品白丝av| www一区二区www免费| 亚洲一区二区三区高清不卡| 啊啊啊国产视频| 国产一区二区三区国产| 国产二级一片内射视频播放| 久久久久久久久一| 永久久久久久久| 天天色天天爱天天射综合| 波多野结衣毛片| 日韩一区二区中文字幕| 神马午夜精品95| 日韩亚洲在线观看| 俺来俺也去www色在线观看| 国产成人一区二区三区| 精品视频在线一区| 久久免费视频1| 伊人久久大香线| 激情五月开心婷婷| 国产美女精品人人做人人爽| 国产精品探花一区二区在线观看| 亚洲国产精品v| 久久精品性爱视频| 欧美在线一区二区三区| 亚洲不卡免费视频| 国产一区二区三区免费视频| 女人黄色免费在线观看| 国产精品www| 久久久久观看| 在线观看视频黄色| 亚洲尤物精选| 国产在线a视频| 国产精品免费久久| 国产一级18片视频| 日韩一级在线观看| 888av在线| 欧美亚洲一级片| 天堂va在线高清一区| 亚洲国产一区二区三区在线| 一本色道久久综合亚洲精品不| 欧美视频国产视频| 久久精品欧美一区二区三区不卡 | 国产有色视频色综合| 午夜精品久久久久久久四虎美女版| 免费看又黄又无码的网站| 国产精品2024| a一级免费视频| 在线视频中文字幕一区二区| 亚洲av毛片成人精品| 欧美成人午夜免费视在线看片| 国产一区二区主播在线| 国外成人免费视频| 国产精品mm| 天天爽夜夜爽视频| 国产精品福利一区二区| 懂色av蜜臀av粉嫩av喷吹| 日韩av在线电影网| v片在线观看| 91在线精品播放| 久久影院一区| 国产福利在线免费| 中文乱码免费一区二区| 一二三区免费视频| 亚洲男女自偷自拍图片另类| 岛国av在线播放| 国产一区二区三区四区hd| 精久久久久久| 大桥未久恸哭の女教师| 亚洲综合男人的天堂| 久久久久久久久久久久久久av| 亚洲国产精品成人va在线观看| 福利网站在线观看| 成人免费在线视频网站| 国产精品97| 久久综合桃花网| 一级中文字幕一区二区| 99久久亚洲精品日本无码| 久久精品视频99| 国产午夜精品一区在线观看 | 99视频一区| 9.1成人看片| 色综合天天视频在线观看| 中文字幕不卡av| 免费在线观看视频a| 麻豆视频在线免费观看| 亚洲国产欧美一区二区三区同亚洲| 国产精品嫩草影视| 欧美极品少妇xxxxⅹ高跟鞋| 亚洲av无码不卡| 中文字幕不卡在线视频极品| 四虎国产精品免费久久| 二级片在线观看| 国产美女久久久久| 国产在线拍揄自揄拍无码视频| 亚洲精品在线网站| 阿v视频在线| 精品久久久久久中文字幕动漫| 亚洲综合社区| 四季av中文字幕| 日韩一区二区三| 韩国精品一区| 热舞福利精品大尺度视频| 极品尤物av久久免费看| 免费一级黄色大片| 国产视频欧美视频| 黄色成人小视频| 青青草视频在线视频| 26uuu久久综合| 在线观看不卡的av| 欧美黄色成人网| 国产传媒欧美日韩成人精品大片| 在线视频日韩一区 | 日韩午夜激情免费电影| 成人bbav| 国产欧美婷婷中文| 欧美精品1区| 人妻丰满熟妇av无码久久洗澡| 神马久久av| 91嫩草免费看| 图片区亚洲欧美小说区| yjizz视频| 欧美自拍偷拍午夜视频| 99热国产在线| 欧美日韩一区二区三区在线观看免| 美女在线视频一区| av大片免费观看| zzjj国产精品一区二区| 日韩欧美中文字幕电影| 午夜啪啪小视频| 日韩欧美在线视频免费观看| 国产精品xxxx喷水欧美| 亚洲伦理中文字幕| 久久国际精品|