亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

spring設置定時任務方式(@Scheduled)

 更新時間:2024年04月15日 09:07:33   作者:雜說  
這篇文章主要介紹了spring設置定時任務方式(@Scheduled),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

以前用過這個注解實現(xiàn)定時任務,但是只是使用,現(xiàn)在做項目又用到了這個功能,系統(tǒng)的學習一下~

spring定時任務設置有兩種方式,注解和xml配置。

推薦使用注解,在本文章也主要介紹注解方式配置

一:注解方式配置定時任務

下面的步驟默認spring的其他配置項都已經配置好(比如啟動注解配置,包路徑掃描等)

1:在spring配置文件中配置,添加命名空間

xmlns添加:

xmlns:task="http://www.springframework.org/schema/task"

xsi:schemaLocation添加 注意"4.3"這是版本號,要修改和你的其他xsd版本號一致

http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd"

啟動注解驅動 注意“dataScheduler”為自定義名稱,可以通過自己的業(yè)務定義 合適 的名稱

<task:annotation-driven scheduler="dataScheduler"/>

開啟任務調度器,并配置線程池大小

  • 注意此處的id指定的就是上面的自定義名稱
  • spring的任務調度默認是單線程的,如果你的項目會有多任務定時執(zhí)行,并且執(zhí)行時間會相交的話,應該根據(jù)任務的具體執(zhí)行情況配置線程池大小
  • 如果不配置線程池,并且A和B任務在同一時間執(zhí)行,A先執(zhí)行的話,B要等待A執(zhí)行完才可以執(zhí)行,AB不會同時執(zhí)行
<task:scheduler id="dataScheduler" pool-size="5"/>

2:使用注解配置定時任務

在你需要配置定時任務的方法上使用注解@Scheduled即可,下面一個簡單案例:

  • 注意 下面的案例是在每天的早上2點執(zhí)行
  • “0 0 2 * * *”是怎么組合的?下面會詳細介紹@Scheduled()注解
@Scheduled(cron = "0 0 2 * * *")
public void init(){
    todo...
}

在此需要注意:@Scheduled只能注釋在無參的方法上,我看網上有許多博客說必須無參無返回值的,但是經過我的測試有返回值是可以的,可能是版本更新了吧。

現(xiàn)在就算是完成spring定時器的使用了,下面讓我們來詳細的看一下@Scheduled注解吧~

二:@Scheduled

@Scheduled注解是Spring專門為定時任務設計的注解

首先,讓我們來看看這個注解是怎么組成的吧(適用于版本JDK8與spring4.3及其以上)

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {

    String cron() default "";
    String zone() default "";
    long fixedDelay() default -1L;
    String fixedDelayString() default "";
    long fixedRate() default -1L;
    String fixedRateString() default "";
    long initialDelay() default -1L;
    String initialDelayString() default "";
}

從上述代碼中看以看出:

1:@Scheduled被注解部分:

  • 元注解@Target表明@Scheduled注解可以在方法上使用(ElementType.METHOD),也可以作為元注解對其他注解進行注解(ElementType.ANNOTATION_TYPE)
  • 元注解@Retention表明此注解會被JVM所保留,也就是會保存在運行時(RetentionPolicy.RUNTIME)
  • 元注解@Documented表明此注解應該被 javadoc工具記錄。默認情況下javadoc是不包括注解的。
  • JDK8添加的注解@Repeatable表明此注解可以在同一個地方被重復使用

上述的所涉及到的注解有不清楚作用的,可以自行baidu\google,網上有好多介紹的文章。

2:@Scheduled參數(shù)部分,總共包含8各部分,我們來分別看一下其作用:

  • cron:一個類似cron的表達式,擴展了通常的UN * X定義,包括秒,分,時,星期,月,年的觸發(fā)器。
  • fixedDelay:在最后一次調用結束和下一次調用開始之間以固定周期(以毫秒為單位)執(zhí)行帶注釋的方法。(要等待上次任務完成后)
  • fixedDelayString:同上面作用一樣,只是String類型
  • fixedRate:在調用之間以固定的周期(以毫秒為單位)執(zhí)行帶注釋的方法。(不需要等待上次任務完成)
  • fixedRateString:同上面作用一樣,只是String類型
  • initialDelay:第一次執(zhí)行fixedRate()或fixedDelay()任務之前延遲的毫秒數(shù) 。
  • initialDelayString:同上面作用一樣,只是String類型
  • zone:指明解析cron表達式的時區(qū)。

cron可以組合出更多的定時情況,fixedDelay和fixedRate只能定義每隔多長時間執(zhí)行一次。

在上述cron、fixedDelay、fixedRate 只能同時存在一個,使用其中一個就不能使用另外的一個,否則會報錯“java.lang.IllegalStateException”

3:cron參數(shù)

一個cron表達式可以有6個元素或者7個元素組成(“年”這個元素可以省略,省略之后就是默認“每一年”)

3.1:按順序依次為:

  • 秒(0~59)
  • 分鐘(0~59)
  • 小時(0~23)
  • 天(0~31)
  • 月(0~11)
  • 星期(1~7 )或者( SUN,MON,TUE,WED,THU,F(xiàn)RI,SAT。其中SUN = 1)
  • 年份(1970-2099)

3.2:每個元素可以接受的值:

字段允許值允許的特殊字符
0-59, - * /
0-59, - * /
小時0-23, - * /
日期1-31, - * ? / L W C
月份1-12 或者 JAN-DEC, - * /
星期1-7 或者 SUN-SAT, - * ? / L C #
空, 1970-2099, - * /

3.3:一些特殊字符解釋與注意事項,可以結合下面的小案例來理解:

其中每個元素可以是一個值(如6),一個連續(xù)區(qū)間(9-12),一個間隔時間(8-18/4)(/表示每隔4小時),一個列表(1,3,5),通配符。

其中的“日”由于"月份中的日期"和"星期"這兩個元素互斥的,必須要對其中一個設置“?”。

有些子表達式能包含一些范圍或列表

  • 例如:子表達式(天(星期))可以為 “MON-FRI”,“MON,WED,F(xiàn)RI”,“MON-WED,SAT”

“*”字符代表所有可能的值

“/”字符用來指定數(shù)值的增量

  • 例如:在子表達式(分鐘)里的“0/15”表示從第0分鐘開始,每15分鐘
  • 在子表達式(分鐘)里的“3/20”表示從第3分鐘開始,每20分鐘(它和“3,23,43”)的含義一樣

“?”字符僅被用于天(月)和天(星期)兩個子表達式,表示不指定值

  • 當2個子表達式其中之一被指定了值以后,為了避免沖突,需要將另一個子表達式的值設為“?”

“L” 字符僅被用于天(月)和天(星期)兩個子表達式,它是單詞“last”的縮寫

  • 如果在“L”前有具體的內容,它就具有其他的含義了。例如:“6L”表示這個月的倒數(shù)第6天
  • 注意:在使用“L”參數(shù)時,不要指定列表或范圍,因為這會導致問題

“W” 字符代表著平日(Mon-Fri),并且僅能用于日域中。它用來指定離指定日的最近的一個平日。大部分的商業(yè)處理都是基于工作周的,所以 W 字符可能是非常重要的。

  • 例如,日域中的 15W 意味著 “離該月15號的最近一個平日。” 假如15號是星期六,那么 trigger 會在14號(星期五)觸發(fā),因為星期四比星期一離15號更近。

“C”:代表“Calendar”的意思。它的意思是計劃所關聯(lián)的日期,如果日期沒有被關聯(lián),則相當于日歷中所有日期。例如5C在日期字段中就相當于日歷5日以后的第一天。1C在星期字段中相當于星期日后的第一天。

3.4:一些小案例:

  • “0 0 10,14,16 * * ?” 每天上午10點,下午2點,4點
  • “0 0/30 9-17 * * ?” 朝九晚五工作時間內每半小時
  • “0 0 12 ? * WED” 表示每個星期三中午12點
  • “0 0 12 * * ?” 每天中午12點觸發(fā)
  • “0 15 10 ? * *” 每天上午10:15觸發(fā)(這個和下一個案例說明,必須"月份中的日期"和"星期"中有一個設置為“?”)
  • “0 15 10 * * ?” 每天上午10:15觸發(fā)
  • “0 15 10 * * ? *” 每天上午10:15觸發(fā)(7個元素類型案例,第七個元素代表年)
  • “0 15 10 * * ? 2005” 2005年的每天上午10:15觸發(fā)
  • “0 * 14 * * ?” 在每天下午2點到下午2:59期間的每1分鐘觸發(fā)
  • “0 0/5 14 * * ?” 在每天下午2點到下午2:55期間的每5分鐘觸發(fā)
  • “0 0/5 14,18 * * ?” 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發(fā)
  • “0 0-5 14 * * ?” 在每天下午2點到下午2:05期間的每1分鐘觸發(fā)
  • “0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44觸發(fā)
  • “0 15 10 ? * MON-FRI” 周一至周五的上午10:15觸發(fā)
  • “0 15 10 15 * ?” 每月15日上午10:15觸發(fā)
  • “0 15 10 L * ?” 每月最后一日的上午10:15觸發(fā)
  • “0 15 10 ? * 6L” 每月的最后一個星期五上午10:15觸發(fā)
  • “0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一個星期五上午10:15觸發(fā)
  • “0 15 10 ? * 6#3” 每月的第三個星期五上午10:15觸發(fā)

到這個地方你應該對@Scheduled有一個較全面的理解了,下面我們就來簡單的看一下其實現(xiàn)原理吧~

三:原理簡介

1:主要過程:

spring在使用applicationContext將類全部初始化。

調用ScheduledAnnotationBeanPostProcessor類中的postProcessAfterInitialization方法獲取項目中所有被注解 @Scheduled注解的方法 。

通過processScheduled方法將所有定時的方法存放在Set tasks = new LinkedHashSet(4); 定時任務隊列中,并解析相應的參數(shù)。順序存放,任務也是順序執(zhí)行。存放順序為cron>fixedDelay>fixedRate

將解析參數(shù)后的定時任務存放在一個初始容量為16 的map中,key為bean name,value為定時任務:private final Map<Object, Set> scheduledTasks = new IdentityHashMap(16);

之后交給ScheduledTaskRegistrar類的方法scheduleTasks去添加定時任務。

2:上述就是一個大致過程,下面看一下相應的源碼:

注意 :spring對定時任務的操作的源碼全部在spring-context.jar包下的org.springframework.scheduling包下面,主要包含三部分:annotation、config、 support,大家有興趣的話可以去看看

1:獲取項目中所有被注解 @Scheduled注解的方法

public Object postProcessAfterInitialization(Object bean, String beanName) {
    Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);
    if (!this.nonAnnotatedClasses.contains(targetClass)) {
        Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, new MetadataLookup<Set<Scheduled>>() {
            public Set<Scheduled> inspect(Method method) {
                //獲取注解方法
                **Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);**
                return !scheduledMethods.isEmpty() ? scheduledMethods : null;
            }
        });
        if (annotatedMethods.isEmpty()) {
            ...
        } else {
            Iterator var5 = annotatedMethods.entrySet().iterator();
            while(var5.hasNext()) {

                Entry<Method, Set<Scheduled>> entry = (Entry)var5.next();
                Method method = (Method)entry.getKey();
                Iterator var8 = ((Set)entry.getValue()).iterator();

                while(var8.hasNext()) {
                    Scheduled scheduled = (Scheduled)var8.next();
                    //將獲取的任務進行參數(shù)解析并存放到任務隊列
                    this.processScheduled(scheduled, method, bean);
                }
            }
           ...
        }
    }
    return bean;
}

2:通過processScheduled方法將所有定時的方法存放在定時任務隊列中

protected void processScheduled(Scheduled scheduled, Method method, Object bean) {
    try {
        ...
        //解析initialDelayString參數(shù)
        String initialDelayString = scheduled.initialDelayString();
        if (StringUtils.hasText(initialDelayString)) {
           ...
        }
        //解析cron參數(shù)
        String cron = scheduled.cron();
        if (StringUtils.hasText(cron)) {
            ...
            //存放到任務隊列中
            tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));
        }
        ...
        //解析fixedDelay參數(shù)
        long fixedDelay = scheduled.fixedDelay();
        if (fixedDelay >= 0L) {
            Assert.isTrue(!processedSchedule, errorMessage);
            processedSchedule = true;
            tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));
        }
        String fixedDelayString = scheduled.fixedDelayString();
        if (StringUtils.hasText(fixedDelayString)) {
            ...
            //存放到任務隊列中
            tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));
        }
        //解析fixedRate參數(shù)
        long fixedRate = scheduled.fixedRate();
        if (fixedRate >= 0L) {
            Assert.isTrue(!processedSchedule, errorMessage);
            processedSchedule = true;
            tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));
        }
        String fixedRateString = scheduled.fixedRateString();
        if (StringUtils.hasText(fixedRateString)) {
            ...
            //存放到任務隊列中
            tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));
        }
        Assert.isTrue(processedSchedule, errorMessage);
        Map var19 = this.scheduledTasks;
        //并發(fā)控制并將任務存放在map中
        synchronized(this.scheduledTasks) {
            Set<ScheduledTask> registeredTasks = (Set)this.scheduledTasks.get(bean);
            if (registeredTasks == null) {
                registeredTasks = new LinkedHashSet(4);
                //將任務存放在map中
                this.scheduledTasks.put(bean, registeredTasks);
            }
            ((Set)registeredTasks).addAll(tasks);
        }
    } catch (IllegalArgumentException var26) {
        throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + var26.getMessage());
    }
}

3:之后交給ScheduledTaskRegistrar類的方法scheduleTasks去添加定時任務

protected void scheduleTasks() {
    if (this.taskScheduler == null) {
        this.localExecutor = Executors.newSingleThreadScheduledExecutor();
        this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
    }
    Iterator var1;
    if (this.triggerTasks != null) {
        var1 = this.triggerTasks.iterator();
        while(var1.hasNext()) {
            TriggerTask task = (TriggerTask)var1.next();
            this.addScheduledTask(this.scheduleTriggerTask(task));
        }
    }
    if (this.cronTasks != null) {
        var1 = this.cronTasks.iterator();
        while(var1.hasNext()) {
            CronTask task = (CronTask)var1.next();
            this.addScheduledTask(this.scheduleCronTask(task));
        }
    }
    IntervalTask task;
    if (this.fixedRateTasks != null) {
        var1 = this.fixedRateTasks.iterator();
        while(var1.hasNext()) {
            task = (IntervalTask)var1.next();
            this.addScheduledTask(this.scheduleFixedRateTask(task));
        }
    }
    if (this.fixedDelayTasks != null) {
        var1 = this.fixedDelayTasks.iterator();
        while(var1.hasNext()) {
            task = (IntervalTask)var1.next();
            this.addScheduledTask(this.scheduleFixedDelayTask(task));
        }
    }
}

此部分只是對原理進行了簡單的介紹,如果有興趣深入了解,可以去看看源碼~

四:其他

做定時任務還可以使用java自帶的原生API,Timer和TimerTask去設計。

  • Timer:一種工具,線程用其安排以后在后臺線程中執(zhí)行的任務??砂才湃蝿請?zhí)行一次,或者定期重復執(zhí)行。
  • TimerTask:定義一個被執(zhí)行的任務,Timer 安排該任務為一次執(zhí)行或重復執(zhí)行的任務。

可以這樣理解Timer是一種定時器工具,用來在一個后臺線程計劃執(zhí)行指定任務,而TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務。

這里就簡單的提一下,并不是本文的重點,具體的用法自行google吧~

總結

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • springboot2版本無法加載靜態(tài)資源問題解決

    springboot2版本無法加載靜態(tài)資源問題解決

    這篇文章主要介紹了springboot2版本無法加載靜態(tài)資源問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • springboot打包無法讀取yml、properties等配置文件的解決

    springboot打包無法讀取yml、properties等配置文件的解決

    這篇文章主要介紹了springboot打包無法讀取yml、properties等配置文件的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2025-04-04
  • springboot中配置好登錄攔截后,swagger訪問不了問題

    springboot中配置好登錄攔截后,swagger訪問不了問題

    這篇文章主要介紹了springboot中配置好登錄攔截后,swagger訪問不了問題及解決,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • java多線程實現(xiàn)有序輸出ABC

    java多線程實現(xiàn)有序輸出ABC

    這篇文章主要為大家詳細介紹了java多線程實現(xiàn)有序輸出ABC,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • Idea配置超詳細圖文教程(2020.2版本)

    Idea配置超詳細圖文教程(2020.2版本)

    這篇文章主要介紹了Idea配置超詳細圖文教程(2020.2版本),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • SpringBoot整合MyBatis實現(xiàn)樂觀鎖和悲觀鎖的示例

    SpringBoot整合MyBatis實現(xiàn)樂觀鎖和悲觀鎖的示例

    這篇文章主要介紹了SpringBoot整合MyBatis實現(xiàn)樂觀鎖和悲觀鎖的示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-09-09
  • Java中的fail-fast機制使用詳解

    Java中的fail-fast機制使用詳解

    fail-fast機制是Java集合中用于檢測并發(fā)修改的一種機制,當一個線程遍歷集合時,如果集合被其他線程修改,就會拋出ConcurrentModificationException異常,解決fail-fast機制的方法包括使用普通for循環(huán)、Iterator
    2025-01-01
  • Springboot如何使用外部yml啟動

    Springboot如何使用外部yml啟動

    這篇文章主要介紹了Springboot如何使用外部yml啟動問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置指南

    SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置指南

    這篇文章主要給大家介紹了關于SpringBoot打印系統(tǒng)執(zhí)行的sql語句及日志配置的相關資料,在Java SpringBoot項目中如果使用了Mybatis框架,默認情況下執(zhí)行的所有SQL操作都不會打印日志,需要的朋友可以參考下
    2023-10-10
  • 【java 多線程】守護線程與非守護線程的詳解

    【java 多線程】守護線程與非守護線程的詳解

    這篇文章主要介紹了java守護線程與非守護線程,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04

最新評論