欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot如何配置定時任務

 更新時間:2020年11月06日 09:43:38   作者:ZY筆記  
這篇文章主要介紹了springboot如何配置定時任務,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下

概述

在Java環(huán)境下創(chuàng)建定時任務有多種方式:

  • 使用while循環(huán)配合 Thread.sleep(),雖然稍嫌粗陋但也勉強可用
  • 使用 Timer和 TimerTask
  • 使用 ScheduledExecutorService
  • 定時任務框架,如Quartz

在SpringBoot下執(zhí)行定時任務無非也就這幾種方式(主要還是后兩種)。只不過SpringBoot做了許多底層的工作,我們只需要做些簡單的配置就行了。

通過注解實現(xiàn)定時任務

在SpringBoot中僅通過注解就可以實現(xiàn)常用的定時任務。步驟就兩步:

在啟動類中添加 @EnableScheduling注解

@EnableScheduling
@SpringBootApplication
public class MyApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
 
}

在目標方法中添加 @Scheduled注解,同時在 @Scheduled注解中添加觸發(fā)定時任務的元數(shù)據(jù)。

    @Scheduled(fixedRate = 1000)
    public void job() {
        System.out.println(Thread.currentThread().getId() + " ----- job1 ----- " + System.currentTimeMillis());
    }

注意: 目標方法需要沒有任何參數(shù),并且返回類型為 void 。

這里的定時任務元數(shù)據(jù)是“fixRate=1000”,意思是固定間隔每1000毫秒即執(zhí)行一次該任務。

再來看幾個 @Schedule注解的參數(shù):

  • fixedRate:設置定時任務執(zhí)行的時間間隔,該值為當前任務啟動時間與下次任務啟動時間之差;
  • fixedDelay:設置定時任務執(zhí)行的時間間隔,該值為當前任務結束時間與下次任務啟動時間之差;
  • cron:通過cron表達式來設置定時任務啟動時間,在Cron Generator網站可以直接生成cron表達式。

這樣創(chuàng)建的定時任務存在一個問題:如存在多個定時任務,這些任務會同步執(zhí)行,也就是說所有的定時任務都是在一個線程中執(zhí)行。

再添幾個定時任務來執(zhí)行下看看:

    @Scheduled(fixedRate = 1000)
    public void job1() {
        System.out.println(Thread.currentThread().getId() + " ----- job1 ----- " + System.currentTimeMillis());
    }
 
    @Scheduled(fixedRate = 1000)
    public void job2() {
        System.out.println(Thread.currentThread().getId() + " ----- job2 ----- " + System.currentTimeMillis());
    }
 
    @Scheduled(fixedRate = 1000)
    public void job3() {
        System.out.println(Thread.currentThread().getId() + " ----- job3 ----- " + System.currentTimeMillis());
    }

代碼中一共創(chuàng)建了三個定時任務,每個定時任務的執(zhí)行間隔都是1000毫秒,在任務體中輸出了執(zhí)行任務的線程ID和執(zhí)行時間。

看下執(zhí)行結果:

20 ----- job3 ----- 1573120568263
20 ----- job1 ----- 1573120568263
20 ----- job2 ----- 1573120568263
20 ----- job3 ----- 1573120569264
20 ----- job1 ----- 1573120569264
20 ----- job2 ----- 1573120569264
20 ----- job3 ----- 1573120570263
20 ----- job1 ----- 1573120570263
20 ----- job2 ----- 1573120570263

可以看到這三個定時任務的執(zhí)行有如下的特點:

  • 所有的定時任務每次都是在同一個線程上執(zhí)行;
  • 雖然未必是job1第一個開始執(zhí)行,但是每批任務的執(zhí)行次序是固定的——這是由fixRate參數(shù)決定的

這樣的定時任務已經能夠覆蓋絕大部分的使用場景了,但是它的缺點也很明顯:前面的任務執(zhí)行時間過長必然會影響之后的任務的執(zhí)行。為了解決這個問題,我們需要異步執(zhí)行定時任務。接下來的部分我們將主要著眼于如何實現(xiàn)異步執(zhí)行定時任務。

通過@Async注解實現(xiàn)異步定時任務

最常用的方式是使用 @Async注解來實現(xiàn)異步執(zhí)行定時任務。啟用 @Async注解的步驟如下:

在啟動類中添加 @EnableAsync注解:

@EnableAsync
@EnableScheduling
@SpringBootApplication
public class MyApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
    
}

在定時任務方法上添加 @Async注解

    @Async
    @Scheduled(fixedRate = 1000)
    public void job1() {
        System.out.println(Thread.currentThread().getId() + " ----- job1 ----- " + System.currentTimeMillis());
    }

我們?yōu)榍懊娴娜齻€定時任務都加上 @Async注解再運行看看:

25 ----- job1 ----- 1573121781415
24 ----- job3 ----- 1573121781415
26 ----- job2 ----- 1573121781415
30 ----- job3 ----- 1573121782298
31 ----- job1 ----- 1573121782299
32 ----- job2 ----- 1573121782299
25 ----- job2 ----- 1573121783304
35 ----- job3 ----- 1573121783306
36 ----- job1 ----- 1573121783306

通過輸出信息可以看到每個定時任務都在不同的線程上執(zhí)行,彼此的執(zhí)行次序和執(zhí)行時間也互不影響,說明配置為異步執(zhí)行已經成功。

通過配置實現(xiàn)異步定時任務

現(xiàn)在我們有必要稍稍深入了解下springboot定時任務的執(zhí)行機制了。

springboot的定時任務主要涉及到兩個接口: TaskScheduler和 TaskExecutor。在springboot的默認定時任務實現(xiàn)中,這兩個接口的實現(xiàn)類是 ThreadPoolTaskScheduler和 ThreadPoolTaskExecutor。

ThreadPoolTaskScheduler負責實現(xiàn)任務的定時執(zhí)行機制,而 ThreadPoolTaskExecutor則負責實現(xiàn)任務的異步執(zhí)行機制。二者中, ThreadPoolTaskScheduler執(zhí)行棧更偏底層一些。

盡管在職責上有些區(qū)別,但是兩者在底層上都是依賴java的線程池機制實現(xiàn)的: ThreadPoolTaskScheduler依賴的底層線程池是 ScheduledExecutorService,springboot默認為其提供的coreSize是1,所以默認的定時任務都是在一個線程中執(zhí)行; ThreadPoolTaskExecutor依賴的底層線程池是 ThreadPoolExecutor,springboot默認為其提供的corePoolSize是8。

說到這里應該清楚了:我們可以不添加 @Async注解,僅通過調整 ThreadPoolTaskScheduler依賴的線程池的coreSize也能實現(xiàn)多線程異步執(zhí)行;同樣的,即使添加了 @Async注解,將 ThreadPoolTaskExecutor依賴的線程池的corePoolSize設置為1,那定時任務還是只能在一個線程上同步執(zhí)行??聪聅pringboot的相關配置項:

spring:
  task:
    scheduling:
      pool:
        size: 1
    execution:
      pool:
        core-size: 2

其中spring.task.scheduling是 ThreadPoolTaskScheduler的線程池配置項,spring.task.execution是 ThreadPoolExecutor的線程池配置項。

再稍稍擴展下: @Async注解的value屬性就是用來指明使用的 TaskExecutor實例的。默認值是空字符串,表示使用的是springboot自啟動的 TaskExecutor實例。如有需要,也可以使用自定義的 TaskExecutor實例,如下:

  /**
     * 配置線程池
     * @return
     */
    @Bean(name = "scheduledPoolTaskExecutor")
    public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(20);
        taskExecutor.setMaxPoolSize(200);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.setKeepAliveSeconds(200);
        taskExecutor.setThreadNamePrefix("my-task-executor-");
        // 線程池對拒絕任務(無線程可用)的處理策略,目前只支持AbortPolicy、CallerRunsPolicy;默認為后者
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //調度器shutdown被調用時等待當前被調度的任務完成
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        //等待時長
        taskExecutor.setAwaitTerminationSeconds(60);
        taskExecutor.initialize();
        return taskExecutor;
    }

此外,還有一種做法是通過提供自定義的 TaskScheduler Bean實例來實現(xiàn)異步執(zhí)行。要提供提供自定義的 TaskScheduler 實例,可以直接通過 @Bean注解聲明創(chuàng)建,也可以在 SchedulingConfigurer接口中配置。這些在后面我們會提到。

調用SpringBoot接口實現(xiàn)定時任務

有時候會需要將定時任務的定時元數(shù)據(jù)寫在數(shù)據(jù)庫或其他配置中心以便統(tǒng)一維護。這種情況就不是通過注解能夠搞定的了,此時我們需要使用springboot定時任務一些組件來自行編程實現(xiàn)。常用的組件包括 TaskScheduler、 Triger接口和 SchedulingConfigurer接口。

注意:因為我們用到了springboot的定時任務組件,所以仍然需要在啟動類上添加 @EnableScheduling注解。

Trigger接口

Trigger接口主要用來設置定時元數(shù)據(jù)。要通過程序實現(xiàn)定時任務就不能不用到這個接口。這個接口有兩個實現(xiàn)類:

  • PeriodicTrigger用來配置固定時長的定時元數(shù)據(jù)
  • CronTrigger用來配置cron表達式定時元數(shù)據(jù)

使用TaskScheduler接口

TaskScheduler接口前面我們提過,這個接口需要配合 Trigger接口一起使用來實現(xiàn)定時任務,看個例子:

 @Autowired
    private TaskScheduler taskScheduler;
 
    public void job() {
        int fixRate = 10;
        taskScheduler.schedule(() -> System.out.println("  job4 ----- " + System.currentTimeMillis()),
                new PeriodicTrigger(fixRate, TimeUnit.SECONDS));
    }

在上面的代碼里,我們使用 @Autowired注解獲取了springbootr容器里默認的 TaskScheduler實例,然后通過 PeriodicTrigger設置了定時元數(shù)據(jù),定時任務的任務體則是一個 Runable接口的實現(xiàn)(在這里只是輸出一行信息)。

因為默認的 TaskScheduler實例的線程池coreSize是1,所以如有多個并發(fā)任務,這些任務的執(zhí)行仍然是同步的。要調整為異步可以在配置文件中配置,也可以通過提供一個自定義的 TaskScheduler實例來設置:

 @Bean("taskScheduler") 
    public TaskScheduler taskExecutor() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setPoolSize(20);
        executor.setThreadNamePrefix("my-task-scheduler");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //調度器shutdown被調用時等待當前被調度的任務完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待時長
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

使用SchedulingConfigurer接口

SchedulingConfigurer接口的主要用處是注冊基于 Trigger接口自定義實現(xiàn)的定時任務。

在實現(xiàn) SchedulingConfigurer接口后,通常還需要使用 @Configuration注解(當然啟動類上的 @EnableScheduling注解也不能少)來聲明它實現(xiàn)類。

這個接口唯一的一個方法就是configureTasks,字面意思是配置定時任務。這個方法最重要的參數(shù)是一個 ScheduledTaskRegistrar定時任務注冊類實例,該類有8個方法,允許我們以不同的方式注冊定時任務。

簡單做了個實現(xiàn):

@Configuration
public class MyTaskConfigurer implements SchedulingConfigurer {
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        
        taskRegistrar
                .addCronTask(
                        () -> System.out.println(Thread.currentThread().getId() + " --- job5 ----- " + System.currentTimeMillis()),
                        "0/1 * * * * ?"
                );
 
        taskRegistrar
                .addFixedDelayTask(
                        () -> System.out.println(Thread.currentThread().getId() + " --- job6 ----- " + System.currentTimeMillis()),
                        1000
                );
 
        taskRegistrar
                .addFixedRateTask(
                        () -> System.out.println(Thread.currentThread().getId() + " --- job7 ----- " + System.currentTimeMillis()),
                        1000
                );
    }
}

這里我們只使用了三種注冊任務的方法,分別嘗試注冊了fixDelay、fixRate以及cron觸發(fā)的定時任務。

springboot會自動啟動注冊的定時任務??聪聢?zhí)行結果:

22 --- job7 ----- 1573613616349
22 --- job6 ----- 1573613616350
22 --- job5 ----- 1573613617001
22 --- job7 ----- 1573613617352
22 --- job6 ----- 1573613617353
22 --- job5 ----- 1573613618065
22 --- job7 ----- 1573613618350
22 --- job6 ----- 1573613618355
22 --- job5 ----- 1573613619002

在執(zhí)行結果中可以看到這里的任務也是在單一線程同步執(zhí)行的。要設置為異步執(zhí)行也簡單,因為 SchedulingConfigurer接口的另一個作用就是為定時任務提供自定義的 TaskScheduler實例。來看下:

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setThreadNamePrefix("my-task-scheduler");
        scheduler.setPoolSize(10);
        scheduler.initialize();
        taskRegistrar.setTaskScheduler(scheduler);
    }

在這里,我將之前注冊的定時任務去掉了,目的是想驗證下這里的配置是否對注解實現(xiàn)的定時任務有效。經檢驗是可行的。當然對在configureTasks方法中配置的定時任務肯定也是有效的。我就不一一貼結果了。

另外,需要注意:如 SchedulingConfigurer接口實例已經注入,將無法再獲取到springboot默認提供的 TaskScheduler接口實例。

通過Quartz實現(xiàn)定時任務

Quartz是一個非常強大的定時任務管理框架。短短的一篇文章未必能介紹清楚Quartz的全部用法。所以這里只是簡單地演示下如何在springboot中是如何使用Quartz的。更多的用法建議優(yōu)先參考Quartz官方文檔。

在spring-boot-web 2.0及之后的版本,已經自動集成了quartz,如果不使用spring-boot-web或使用較早的版本的話我們還需要加一些依賴:

 <!-- quartz -->
    <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
    </dependency>
    <!-- spring集成quartz -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context-support</artifactId>
    </dependency>
    <!-- SchedulerFactoryBean依賴了tx包中的PlatformTransactionManager類,因為quartz的分布式功能是基于數(shù)據(jù)庫完成的 -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>

添加完成這些依賴后,springboot服務在啟動時也會自啟動內部的quartz。事實上springboot已經為我們準備好了幾乎全部的quartz的配置。我們要做的只是把自定義的任務填進去。

首先我們需要創(chuàng)建一個Job實例,來實現(xiàn)Job的具體行為。

@Component
public class MyQuartzJob extends QuartzJobBean {
 
    @Override
    protected void executeInternal(JobExecutionContext context) {
        JobDataMap map = context.getMergedJobDataMap();
        // 從作業(yè)上下文中取出Key
        String key = map.getString("key");
        System.out.println(Thread.currentThread().getId() + " -- job8 ---------------------->>>>" + key);
    }
 
}

QuartzJobBean是Spring提供的Quartz Job抽象類。在實現(xiàn)這個類的時候我們可以獲取注入到spring中的其他Bean。

配置Job

@Configuration
public class QuartzConfig implements InitializingBean {
 
    @Autowired
    private SchedulerFactoryBean schedulerFactoryBean;
 
 
    @Override
    public void afterPropertiesSet() throws Exception {
        config();
    }
 
 
    private void config() throws SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
 
        JobDetail jobDetail = buildJobDetail();
        Trigger trigger = buildJobTrigger(jobDetail);
        scheduler.scheduleJob(jobDetail, trigger);
    }
 
 
    private JobDetail buildJobDetail() {
        // 用來存儲交互信息
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("key", "zhyea.com");
 
        return JobBuilder.newJob(MyQuartzJob.class)
                .withIdentity(UUID.randomUUID().toString(), "chobit-job")
                .usingJobData(dataMap)
                .build();
    }
 
 
    private Trigger buildJobTrigger(JobDetail jobDetail) {
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail)
                .withIdentity(jobDetail.getKey().getName(), "chobit-trigger")
                .withSchedule(CronScheduleBuilder.cronSchedule("0/1 * * * * ?"))
                .build();
    }
}

在創(chuàng)建 QuartzConfig類的時候實現(xiàn)了 InitializingBean接口,目的是在 QuartzConfig實例及依賴類都完成注入后可以立即執(zhí)行配置組裝操作。

這里面有幾個關鍵接口需要說明下:

  • SchedulerFactoryBean,Quartz Scheduler工廠類,springboot自動化配置實現(xiàn);
  • Scheduer,負責Quartz Job調度,可從工廠類實例獲??;
  • JobDetail,執(zhí)行Quartz Job封裝;
  • Trigger,完成Quartz Job啟動。

還可以在配置文件中添加Quartz的配置:

spring:
  quartz:
    startupDelay: 180000 #這里是毫秒值

這里配置了讓Quartz默認延遲啟動3分鐘。

看下執(zhí)行結果:

30 -- job8 ---------------------->>>>zhyea.com
31 -- job8 ---------------------->>>>zhyea.com
32 -- job8 ---------------------->>>>zhyea.com
33 -- job8 ---------------------->>>>zhyea.com
34 -- job8 ---------------------->>>>zhyea.com
...

好了,就這些內容了。前面用到的程序都上傳到了GITHUB,有需要可以參考下。

參考文檔

Spring Task Execution and Scheduling
Scheduling Tasks
SpringBoot Quartz Scheduler
Spring Boot Quartz Scheduler Example: Building an Email Scheduling app
Quartz Scheduler Tutorials

以上就是springboot如何配置定時任務的詳細內容,更多關于springboot配置定時任務的資料請關注腳本之家其它相關文章!

相關文章

  • Java 實戰(zhàn)練手項目之醫(yī)院預約掛號系統(tǒng)的實現(xiàn)流程

    Java 實戰(zhàn)練手項目之醫(yī)院預約掛號系統(tǒng)的實現(xiàn)流程

    讀萬卷書不如行萬里路,只學書上的理論是遠遠不夠的,只有在實戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SpringBoot+Maven+Vue+mysql實現(xiàn)一個醫(yī)院預約掛號系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2021-11-11
  • JAVA中的SPI思想介紹

    JAVA中的SPI思想介紹

    大家好,本篇文章主要講的是JAVA中的SPI思想介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下
    2022-01-01
  • MyBatis結果映射(ResultMap)的使用

    MyBatis結果映射(ResultMap)的使用

    在MyBatis中,結果映射是實現(xiàn)數(shù)據(jù)庫結果集到Java對象映射的核心,它不僅支持簡單的字段映射,還能處理字段名不一致、嵌套對象和集合映射等復雜場景,通過ResultMap,開發(fā)者可以靈活定義映射關系,以適應各種需求,感興趣的可以了解一下
    2024-09-09
  • Spring?Boot獲取resources目錄下的文件三種方式詳解

    Spring?Boot獲取resources目錄下的文件三種方式詳解

    在Spring?Boot項目中,經常需要獲取resources目錄下的文件,這些文件可以包括配置文件、模板文件、靜態(tài)資源等,這篇文章主要介紹了Spring?Boot獲取resources目錄下的文件的三種方式,需要的朋友可以參考下
    2023-06-06
  • SpringBoot項目中遇到的BUG問題及解決方法

    SpringBoot項目中遇到的BUG問題及解決方法

    這篇文章主要介紹了SpringBoot項目中遇到的BUG問題及解決方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • java實現(xiàn)簡單解析XML文件功能示例

    java實現(xiàn)簡單解析XML文件功能示例

    這篇文章主要介紹了java實現(xiàn)簡單解析XML文件功能,結合實例形式分析了java針對xml文件的讀取、遍歷節(jié)點及輸出等相關操作技巧,需要的朋友可以參考下
    2017-10-10
  • SpringCloud容器化服務發(fā)現(xiàn)及注冊實現(xiàn)方法解析

    SpringCloud容器化服務發(fā)現(xiàn)及注冊實現(xiàn)方法解析

    這篇文章主要介紹了SpringCloud容器化服務發(fā)現(xiàn)及注冊實現(xiàn)方法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-08-08
  • java實現(xiàn)一個簡單的網絡爬蟲代碼示例

    java實現(xiàn)一個簡單的網絡爬蟲代碼示例

    這篇文章主要介紹了java實現(xiàn)一個簡單的網絡爬蟲代碼示例,還是挺不錯的,這里分享給大家,需要的朋友可以參考下。
    2017-11-11
  • JAVA 對接騰訊云直播的實現(xiàn)

    JAVA 對接騰訊云直播的實現(xiàn)

    這篇文章主要介紹了JAVA 對接騰訊云直播的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-06-06
  • Java?this關鍵字的使用案例詳解

    Java?this關鍵字的使用案例詳解

    這篇文章主要為大家介紹了Java?this關鍵字的使用,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01

最新評論