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

Spring中Cron表達式的優雅實現方案

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

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

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

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

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

可變與不可變

默認情況下,@Scheduled注解標記的定時任務方法在初始化之后,是不會再發生變化的。Spring 在初始化 bean 后,通過后處理器攔截所有帶有@Scheduled注解的方法,并解析相應的的注解參數,放入相應的定時任務列表等待后續統一執行處理。到定時任務真正啟動之前,我們都有機會更改任務的執行周期等參數。

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

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

創造與毀滅

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

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

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

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

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

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

@Configuration
@EnableAsync
@EnableScheduling
public class SchedulingConfiguration implements SchedulingConfigurer, ApplicationContextAware {
    private static final Logger log = LoggerFactory.getLogger(SchedulingConfiguration.class);
    private static ApplicationContext appCtx;
    private final ConcurrentMap<String, ScheduledTask> scheduledTaskHolder = new ConcurrentHashMap<>(16);
    private final 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
public class CronTaskLoader implements ApplicationRunner {
    private static final Logger log = LoggerFactory.getLogger(CronTaskLoader.class);
    private final SchedulingConfiguration schedulingConfiguration;
    private final AtomicBoolean appStarted = new AtomicBoolean(false);
    private final 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
public class CronTaskFoo implements IPollableService {
    private static final Random random = new SecureRandom();

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

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

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

@Service
public class CronTaskUnavailable implements IPollableService {
    private String cronExpression = "-";
    private static final 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等額外的中間件,可以說是十分的輕量和優雅了。

責任編輯:武曉燕 來源: 一安未來
相關推薦

2025-04-21 02:20:00

2024-02-02 12:41:33

表達式語法Cron

2024-06-03 00:00:01

表達式PythonJava

2024-04-30 08:05:15

Rust代碼計算

2024-03-25 13:46:12

C#Lambda編程

2017-08-16 16:41:04

JavaSpringBoot定時任務

2024-10-10 14:43:54

LambdaSpring編程

2010-03-25 18:25:36

Python正則表達式

2014-01-05 17:41:09

PostgreSQL表達式

2022-01-14 07:56:39

C#動態查詢

2010-09-10 15:20:11

SQL函數計算表達式

2020-11-04 09:23:57

Python

2009-07-21 14:03:00

Scalaif表達式while循環

2009-07-09 09:51:07

Lambda表達式C#

2009-08-10 09:41:07

.NET Lambda

2024-02-29 07:28:44

Cron表達式解析庫

2009-09-16 13:24:30

PHP正則表達式匹配

2018-09-27 15:25:08

正則表達式前端

2010-07-14 10:06:55

Perl正則表達式

2009-06-12 09:44:04

LINQ查詢復合from子句
點贊
收藏

51CTO技術棧公眾號

日韩脚交footjobhd| 国产精品怡红院| 一区三区在线欧| 欧美伊人精品成人久久综合97| 亚洲一区不卡在线| www.国产.com| 国产精品入口| 久久精品久久久久久国产 免费| 欧美xxxx日本和非洲| 中文在线免费二区三区| 亚洲视频中文字幕| 国模一区二区三区私拍视频| 在线免费观看av片| 亚洲免费大片| 久久影视电视剧免费网站| 看全色黄大色黄女片18| 九九久久国产| 亚洲主播在线播放| 亚洲欧美日韩在线综合| 亚洲三级中文字幕| 国产一区免费电影| 国产精品r级在线| 久久精品免费av| 国产精品久久久久久久| 亚洲欧洲中文天堂| 国产精品成人99一区无码 | 久久综合久久色| 日本h片在线| 国产精品网站一区| 久久青青草原一区二区| 亚洲AV无码一区二区三区性| 久久精品国产精品青草| 青青在线视频一区二区三区| 国产免费久久久久| 加勒比久久综合| 精品视频在线播放| 影音先锋黄色资源| 9l亚洲国产成人精品一区二三| 欧美日韩亚洲综合一区二区三区| 国精产品一区一区三区视频| 蜜臀av在线| 亚洲精品免费一二三区| 在线看成人av电影| 91精品专区| 国产色综合久久| 久久精品国产一区二区三区不卡| 空姐吹箫视频大全| 风流少妇一区二区| aa成人免费视频| 亚洲xxx在线| 丰满岳乱妇一区二区三区| 91夜夜揉人人捏人人添红杏| 国产一区二区三区在线观看| 日韩精品三区四区| 欧美在线视频免费播放| 秋霞精品一区二区三区| 毛片一区二区| 国产精品福利网站| 中文字幕av免费观看| 免费精品视频在线| 成人免费观看a| 99久久免费国产精精品| 国产精品18久久久久久久久久久久| 91精品视频在线看| 精品国产一级片| 国产成人精品网址| 国产精品二区在线观看| 欧美 日韩 国产 在线| 99精品视频在线观看| 国产一区二区三区黄| 欧美在线观看在线观看| 国产免费久久精品| 蜜臀av.com| 麻豆国产在线| 欧美性生活久久| 手机免费看av网站| 日韩一区网站| 国产视频自拍一区| 粉嫩精品久久99综合一区| 91成人精品视频| 欧美福利小视频| 亚洲欧美日韩激情| 久久国产视频网| 国产精品视频500部| 免费人成在线观看网站| 中文字幕 久热精品 视频在线| 国产精品亚洲天堂| 成人免费观看在线观看| 欧美色倩网站大全免费| 成人做爰69片免费| 欧美日韩中文一区二区| 欧美大奶子在线| 黄色一级片免费在线观看| 免费成人在线网站| 国产欧美日韩综合精品二区| 国产乱视频在线观看| 亚洲精品欧美在线| 久章草在线视频| 精品国产一区二区三区性色av| 亚洲国内精品视频| 一级性生活免费视频| 激情五月***国产精品| 国产精品国产三级国产aⅴ浪潮| 国产av无码专区亚洲a∨毛片| 91在线视频免费观看| 欧美爱爱视频网站| 中文字幕乱码在线播放| 日韩欧美国产不卡| 免费网站在线高清观看| 国产精品激情| 成人福利在线观看| 精品视频一二区| 亚洲一区二区在线免费观看视频 | 日韩av影片在线观看| 亚洲AV成人无码网站天堂久久| 亚洲久久视频| 91aaaa| 一广人看www在线观看免费视频| 欧美日韩精品在线播放| 国产999免费视频| 成人免费在线观看av| 91精品国产高清自在线| www久久久久久| 中文字幕制服丝袜成人av| av天堂永久资源网| 风间由美一区二区av101| 精品国产依人香蕉在线精品| jizz国产在线| 久久久777精品电影网影网| 国产精品国产对白熟妇| 试看120秒一区二区三区| 日韩中文字幕精品视频| 日批视频免费观看| 久久久亚洲精品石原莉奈| 蜜桃传媒一区二区三区| y111111国产精品久久久| 欧美成人免费全部观看天天性色| 一级片视频网站| 国产精品久久久久四虎| 日本久久久久久久久久久久| 自拍欧美一区| 国产成人97精品免费看片| 青青青手机在线视频观看| 婷婷一区二区三区| 国产十八熟妇av成人一区| 欧美日韩理论| 国产精品一区二区三区免费观看 | 亚洲欧美日韩国产综合| 三级av免费观看| 成人羞羞在线观看网站| 国产精品久久网| 91在线播放网站| 欧美日韩精品一区二区三区四区 | 91成人免费在线| 亚洲码无人客一区二区三区| 老牛国产精品一区的观看方式| 久久久综合亚洲91久久98| 亚洲欧美小说色综合小说一区| 日韩av中文在线| 日韩视频在线观看一区| 国产日韩欧美精品综合| 五月天av在线播放| 成人免费观看视频大全| 免费观看久久久4p| 亚洲精品成人久久久998| 成人午夜一级| 国产一区二区欧美日韩| 伊人网视频在线| 亚洲精品中文字幕乱码三区| 欧美熟妇精品一区二区| 亚洲欧洲日本mm| 欧美一区二区三区成人久久片| 456亚洲精品成人影院| 中文字幕国内精品| 国产黄色一级大片| 欧美性xxxxx极品娇小| 91成人在线免费视频| 久久爱www久久做| 成年人深夜视频| 偷拍自拍亚洲色图| 国产精品主播视频| 欧美videos另类精品| 亚洲精品中文字幕女同| 中文字幕一区二区三区波野结 | 成人在线免费观看网址| 国产精品高潮呻吟久久久久| 国产成人精彩在线视频九色| 麻豆网在线观看| 精品国产乱码久久久久久久| 国产精品视频一区在线观看| ...中文天堂在线一区| 亚洲中文字幕无码一区| 蜜桃av一区二区| 欧美高清中文字幕| 亚洲天堂日韩在线| 999热视频| 中文字幕av一区二区三区佐山爱| 久久国产精彩视频| 韩日在线视频| 精品久久久久久久久久久久包黑料 | 青青在线视频免费观看| 亚洲小说图片视频| 91在线观看免费观看| 欧美一区久久久| 欧美巨猛xxxx猛交黑人97人| 极品美乳网红视频免费在线观看| 日韩欧美国产电影| 在线观看国产黄| 精品日本高清在线播放 | 日本成人一区二区三区| 91精品国产综合久久久蜜臀粉嫩| 国产精品男女视频| 一区二区三区久久| 在线观看天堂av| 99re66热这里只有精品3直播| 国产又粗又长又爽又黄的视频| 久久精品系列| 免费成人午夜视频| 欧美日韩国产探花| 国产高清免费在线| 成人精品影视| 欧美一区二区三区四区五区六区| 亚洲精品影片| 亚洲影院高清在线| 久久久久伊人| 国产精品成人播放| 性爽视频在线| 97在线观看免费高清| 五月天激情在线| 久久最新资源网| 美女黄视频在线观看| 中文字幕av一区二区| 欧美理论在线观看| 亚洲精品小视频| 四虎在线视频免费观看| 精品日韩一区二区三区免费视频| 国产日韩免费视频| 在线不卡免费欧美| 91av久久久| 欧美日韩日日摸| 一区二区乱子伦在线播放| 色婷婷av一区二区三区之一色屋| 国产一区二区99| 欧美日韩国产一区二区| 国产成人一区二区三区影院在线| 无吗不卡中文字幕| 亚洲视频免费播放| 欧美日韩另类字幕中文| 日韩精品在线免费视频| 精品国产乱码久久久久酒店| 黄色在线观看国产| 一本色道久久综合亚洲aⅴ蜜桃 | 极品美鲍一区| 91po在线观看91精品国产性色| 日本在线啊啊| 国产91色在线| 久久69成人| 91色视频在线导航| 亚洲精品a区| 国产伦精品一区二区三区免 | 亚洲欧美在线一区二区| 国产中文字幕在线观看| 一夜七次郎国产精品亚洲| 欧美被日视频| 色与欲影视天天看综合网| 黄网站在线观| 欧美综合激情网| 精品视频在线一区二区在线| 91精品久久久久久久久中文字幕 | 日韩欧美精品在线视频| 亚洲国产精品suv| 日韩av中文字幕在线| 成人亚洲综合天堂| 久久人人爽人人爽爽久久| 丁香花在线观看完整版电影| 2019av中文字幕| 本网站久久精品| 亚洲精品欧美日韩专区| 久久九九热re6这里有精品| 日韩av电影免费在线| 91精品国产福利在线观看麻豆| 成人在线视频一区二区三区| 欧美亚洲一区| 丰满少妇中文字幕| 91免费精品国自产拍在线不卡| 国产成人免费观看网站| 一区二区三区四区在线播放| www亚洲视频| 91麻豆精品国产91久久久久| 亚洲av片在线观看| 日韩视频免费看| 亚洲国产福利| 亚洲一区二区三| 国产不卡av一区二区| 伊人网在线免费| 久久福利精品| 激情综合激情五月| 欧美激情一二三区| 国语对白一区二区| 欧美男同性恋视频网站| 色噜噜在线播放| 久久深夜福利免费观看| 国产精品专区免费| 风间由美一区二区三区| 色综合天天爱| 国产日韩一区二区在线观看| 国产精品一区二区在线播放| 色一情一交一乱一区二区三区| 亚洲一区二区三区在线看| 中文字幕日产av| 精品无人国产偷自产在线| 性欧美video高清bbw| 国产精品一区专区欧美日韩| 亚洲最好看的视频| 国产成人永久免费视频| 久国产精品韩国三级视频| 久久av无码精品人妻系列试探| 亚洲国产日韩av| 国产av精国产传媒| 久久久99免费视频| 巨胸喷奶水www久久久免费动漫| 久久www免费人成精品| 欧美午夜在线视频| 在线视频日韩欧美| 国产精品国产三级国产专播品爱网| 国产精品久久久久久久久久精爆| 亚洲精品在线免费播放| av片在线观看永久免费| 国产欧美中文字幕| 成人亚洲一区| 91人人澡人人爽人人精品| 久久久久久久综合色一本| 圆产精品久久久久久久久久久| 日韩美女一区二区三区| 中文字幕在线观看网站| 成人激情视频免费在线| 久久国产成人精品| 欧美男女交配视频| 欧美国产禁国产网站cc| 中文天堂在线播放| 中文字幕欧美专区| 精品美女一区| 久久免费视频2| 国产一区二区三区视频在线播放| 国产又色又爽又高潮免费| 欧美日本国产视频| 麻豆视频免费在线观看| 国产欧美一区二区三区在线| 色综合咪咪久久网| 捷克做爰xxxⅹ性视频| 亚洲色大成网站www久久九九| 国产一区二区在线视频聊天| 日韩有码视频在线| 美女久久精品| 国产在线视频在线| 不卡一卡二卡三乱码免费网站| 日本在线视频免费| 日韩电影大片中文字幕| 国产伦精品一区二区三区视频金莲| 欧美大香线蕉线伊人久久国产精品| 麻豆成人精品| 精品视频第一页| 91精品免费观看| 丁香花在线电影小说观看| 久久精品第九区免费观看| 欧美专区在线| 人人艹在线视频| 日韩一级免费一区| 激情黄产视频在线免费观看| 日本一区二区精品| 国产精品影视在线观看| 精品无码人妻一区二区三区| 日韩精品日韩在线观看| 亚洲第一会所001| 欧美性受黑人性爽| 成人黄色在线网站| 无码人妻一区二区三区免费| 北条麻妃一区二区三区中文字幕| 欧美2区3区4区| 欧美亚洲一二三区| 国产精品久久久一本精品| 国产黄色美女视频| 热久久这里只有精品| 97偷自拍亚洲综合二区| 亚洲成人精品在线播放| 一本大道久久精品懂色aⅴ| 免费网站免费进入在线| 国产午夜精品一区| 麻豆一区二区99久久久久| 国产一级做a爰片在线看免费| 亚洲色图综合网| 97色婷婷成人综合在线观看| 少妇av一区二区三区无码| 国产精品嫩草影院av蜜臀| 蜜桃视频污在线观看| 国产精品色婷婷视频| 激情成人亚洲| 欧美h片在线观看| 亚洲视频在线看| 国产精品中文字幕制服诱惑|