Spring 定時任務 SchedulingConfigurer 接口


在 Spring 中,創建簡單的定時任務可以使用 @Scheduled 注解,但它有一個缺點,其定時的時間不能動態的改變,而使用基於 SchedulingConfigurer 接口的方式可以做到。

@Scheduled

/*
cron表達式語法:[秒] [分] [小時] [日] [月] [周] [年]
@Scheduled(fixedDelay = 5000) //上一次執行完畢時間點之后5秒再執行
@Scheduled(fixedDelayString = "5000") //上一次執行完畢時間點之后5秒再執行
@Scheduled(fixedRate = 5000) //上一次開始執行時間點之后5秒再執行
@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延遲1秒后執行,之后按fixedRate的規則每5秒執行一次
*/
// 標記配置類
@Configuration
// 開啟定時任務
@EnableScheduling
public class Schedule {
  @Scheduled(cron = "0/5 * * * * ?")
  private void configureTasks() {
    System.err.println("基於注解(@Scheduled)的簡單定時器demo: " + LocalDateTime.now());
  }
}

SchedulingConfigurer

SchedulingConfigurer 接口可以實現在 @Configuration 類上,同時不要忘記需要 @EnableScheduling 注解。

該接口的實現方法如下:

public void configureTasks(ScheduledTaskRegistrar taskRegistrar)

其中 ScheduledTaskRegistrar 類的方法有 Trigger 觸發的任務、基於 Cron 表達式的任務、定時任務和延時任務。

以 TriggerTask 為例,示例如下:

@Configuration
@EnableScheduling
public class ConfigurerScheduling implements SchedulingConfigurer{
  
  @Override
  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.addTriggerTask(
      // 執行定時任務
      () ->{
        System.out.println("基於接口SchedulingConfigurer的動態定時任務:"
            + LocalDateTime.now()+",線程名稱:"+Thread.currentThread().getName()
            + " 線程id:"+Thread.currentThread().getId());
      }, 
      // 設置觸發器
      triggerContext -> {
        return new CronTrigger("0/5 * * * * ?").nextExecutionTime(triggerContext);
      }
    );
  }
}

Thread

默認的,SchedulingConfigurer 使用的也是單線程的方式,如果需要配置多線程,則需要指定 PoolSize

@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
  ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
  taskScheduler.setPoolSize(10);
  taskScheduler.initialize();
  taskRegistrar.setTaskScheduler(taskScheduler);
//  taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
  taskRegistrar.addTriggerTask(...);
}

SpringBoot Demo

pom 依賴

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.6.RELEASE</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
</dependencies>

yml 配置文件

#設置定時任務 
task: 
  taskName1: #任務名稱 
    switch: true #是否開啟定時任務
    cron: "0/5 * * * * ?" #任務表達式 
  taskName2:  
    switch: true 
    cron: "0/5 * * * * ?" 

SchedulingConfigurer

@Configuration
@EnableScheduling
public abstract class ConfigurerSchedule implements SchedulingConfigurer{

  private String cron;
  
  @Override
  public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
    taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    taskRegistrar.addTriggerTask(
      // 執行定時任務
      () ->{
        processTask();
      },
      // 設置觸發器
      triggerContext -> {
              if (StringUtils.isEmpty(cron)) {
                cron = getCron();
              }
            return new CronTrigger(cron).nextExecutionTime(triggerContext);
      }
        );
    }
    
    /**
     * @brief 任務的處理函數
     * 本函數需要由派生類根據業務邏輯來實現
     */
    protected abstract void processTask();


    /**
     * @return String
     * @brief 獲取定時任務周期表達式
     * 本函數由派生類實現,從配置文件,數據庫等方式獲取參數值
     */
    protected abstract String getCron();
    
}

TaskDemo

@Configuration
public class TaskDemo1 extends ConfigurerSchedule{
  
  @Value(value = "${task.taskName1.switch}")
  private Boolean isSwitch;
  
  @Value(value = "${task.taskName1.cron}")
  private String cron;
  
  @Override
  protected void processTask() {
      if (isSwitch){
          System.out.println("基於接口SchedulingConfigurer的動態定時任務:"
                  + LocalDateTime.now()+",線程名稱:"+Thread.currentThread().getName()
                  + " 線程id:"+Thread.currentThread().getId());
      }
  }
  
  @Override
  protected String getCron() {
      return cron;
  }
}
@Configuration
public class TaskDemo2 extends ConfigurerSchedule{

  @Value(value = "${task.taskName2.switch}")
  private Boolean isSwitch;
  
  @Value(value = "${task.taskName2.cron}")
  private String cron;
  
  @Override
  protected void processTask() {
      if (isSwitch) {
          System.out.println("基於接口SchedulingConfigurer的動態定時任務:"
              + LocalDateTime.now() + ",線程名稱:" + Thread.currentThread().getName()
              + " 線程id:" + Thread.currentThread().getId());
      }
  }
  
  @Override
  protected String getCron() {
      return cron;
  }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM