成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

SpringBoot3優雅停止/重啟定時任務

開發 前端
在Spring Boot中,使用@Scheduled注解可以方便地創建定時任務。然而,隨著應用程序的復雜性和運維需求的增加,動態管理這些定時任務成為了一個重要的問題。針對這種動態管理定時任務Spring Boot中并沒有提供相應的實現,所以就需要我們自己動手來實現定時任務的管理。

環境:SpringBoot3.2.5

1. 簡介

在Spring Boot中,使用@Scheduled注解可以方便地創建定時任務。然而,隨著應用程序的復雜性和運維需求的增加,動態管理這些定時任務成為了一個重要的問題。針對這種動態管理定時任務Spring Boot中并沒有提供相應的實現,所以就需要我們自己動手來實現定時任務的管理。

2. 執行原理

首先,我們要搞清楚Spring Boot定時任務的執行原理,其核心先通過ScheduledAnnotationBeanPostProcessor處理器,找到所有的Bean中使用了@Scheduled注解的方法,然后將對應的方法包裝到Runnable中。

public class ScheduledAnnotationBeanPostProcessor {
  public Object postProcessAfterInitialization(Object bean, String beanName) {
    // 找到符合條件的方法
    Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
      (MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
        Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(
            method, Scheduled.class, Schedules.class);
        return (!scheduledAnnotations.isEmpty() ? scheduledAnnotations : null);
      });
    // 處理方法,在processScheduled方法中會將任務包裝成ScheduledMethodRunnable對象
    annotatedMethods.forEach((method, scheduledAnnotations) ->
      scheduledAnnotations.forEach(scheduled -> processScheduled(scheduled, method, bean))); 
  }
}

接下來,就是通過TaskScheduler來執行定時任務,該接口提供了一些列的方法:

public interface TaskScheduler {
  // 這些調用任務都返回了Future
  ScheduledFuture<?> schedule(Runnable task, Trigger trigger) ;


  ScheduledFuture<?> schedule(Runnable task, Instant startTime);


  ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Instant startTime, Duration period);


  // 還有其它方法。
}

在默認情況下,Spring Boot定時任務的執行線程池使用的是ThreadPoolTaskSchedulerBean。內部真正任務調用是通過ScheduledExecutorService執行定時任務。

所以,要實現動態管理任務,就需要記錄下每個任務信息。記錄任務信息是為了停止任務及再次啟動任務,在上面的調度方法都返回了Future對象,可以通過該Future對象來終止任務,可以通過再次調用schedule方法來再次啟動任務。所以,我們需要自定義TaskScheduler,在自定義的實現中我們就能很方便的記錄管理每個定時任務。

3. 實戰案例

要管理任務,我們就必須為每個任務提供一個有意義的名稱。@Scheduled注解并沒有提供此功能。所以這塊功能,需要自己實現。

3.1 自定義@Task注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Task {
  /**任務名稱*/
  String value() default "" ;
}

該注解用來對任務的說明。

3.2 任務信息TaskInfo

public class TaskInfo {
  private Runnable task ;
  private Instant startTime ;
  private Trigger trigger ;
  private Duration period ;
  private Duration delay ;
  private ScheduledFuture<?> future ;
}

該類用來在執行任務前記錄當前的信息,以便可以對任務進行停止和重啟。

3.3 自定義線程池

@Component
public class PackTaskScheduler extends ThreadPoolTaskScheduler {
  
  private static final Map<String, TaskInfo> TASK = new ConcurrentHashMap<>() ;
  @Override
  public ScheduledFuture<?> schedule(Runnable task, Trigger trigger) {
    ScheduledFuture<?> schedule = super.schedule(task, trigger) ;
    if (task instanceof ScheduledMethodRunnable smr) {
      String taskName = parseTask(smr);
      TASK.put(taskName, new TaskInfo(task, null, trigger, null, null, schedule)) ;
    }
    return schedule ;
  }
  // 還有其它重寫的方法,自行實現
  private String parseTask(ScheduledMethodRunnable smr) {
    Method method = smr.getMethod();
    Task t = method.getAnnotation(Task.class) ;
    String taskName = method.getName() ; 
    if (t != null) {
      String value = t.value() ;
      if (StringUtils.hasLength(value)) {
        taskName = value ;
      }
    }
    return taskName ;
  }


  public void stop(String taskName) {
    TaskInfo task = TASK.get(taskName) ;
    if (task != null) {
      task.getFuture().cancel(true) ;
    }
  }
  public void start(String taskName) {
    TaskInfo task = TASK.get(taskName) ;
    if (task != null) {
      if (task.trigger != null) {
        this.schedule(task.getTask(), task.getTrigger()) ;
      }
      if (task.period != null) {
        this.scheduleAtFixedRate(task.getTask(), task.getPeriod()) ;
      }
    }
  }
}

該類的核心作用就2個:1. 重寫任務調度方法,記錄任務信息2. 添加停止/重啟任務調度也可以考慮在該類中實現任務的持久化。

以上就完成了所有的核心操作。接下來寫2個方法進行測試。

3.4 測試

定時任務

@Scheduled(cron = "*/3 * * * * *")
@Task("測試定時任務-01")
public void scheduler() throws Exception {
  System.err.printf("當前時間: %s, 當前線程: %s, 是否虛擬線程: %b%n", new SimpleDateFormat("HH:mm:ss").format(new Date()), Thread.currentThread().getName(), Thread.currentThread().isVirtual()) ;
}

停止/重啟接口

private final PackTaskScheduler packTaskScheduler ;
public SchedulerController(PackTaskScheduler packTaskScheduler) {
  this.packTaskScheduler = packTaskScheduler ;
}
@GetMapping("stop")
public Object stop(String taskName) {
  this.packTaskScheduler.stop(taskName) ;
  return String.format("停止任務【%s】成功", taskName) ;
}
@GetMapping("/start") 
public Object start(String taskName) {
  this.packTaskScheduler.start(taskName) ;
  return String.format("啟動任務【%s】成功", taskName) ; 
}

分別調用上面2個方法可以對具體的任務進行停止及重啟。

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2024-09-03 10:44:32

2019-02-20 15:52:50

技術開發代碼

2017-08-16 16:41:04

JavaSpringBoot定時任務

2024-02-28 09:54:07

線程池配置

2024-09-20 05:49:04

SpringBoot后端

2025-02-24 16:00:00

SpringBoot定時任務開發

2023-08-07 14:28:07

SpringBoot工具

2025-04-21 02:20:00

2009-10-28 10:05:29

Ubuntucrontab定時任務

2012-02-07 13:31:14

SpringJava

2010-03-10 15:47:58

crontab定時任務

2023-01-04 09:23:58

2024-09-09 08:11:12

2023-08-09 08:29:51

SpringWeb編程

2023-10-31 12:42:00

Spring動態增刪啟停

2021-06-30 07:19:34

SpringBoot定時任務

2024-11-04 16:01:01

2020-12-21 07:31:23

實現單機JDK

2010-01-07 13:38:41

Linux定時任務

2024-12-27 08:24:55

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩成人在线网站 | 成人在线视频一区 | 日本a在线 | 国产乱码精品1区2区3区 | 一区二区三区四区日韩 | 国产三级在线观看播放 | 免费激情 | 日本久久网| 亚洲一区二区免费视频 | 亚洲成人av一区二区 | 日韩在线视频一区二区三区 | 欧美1区2区| 久久99精品久久久久久 | 日韩精品在线网站 | 亚洲 自拍 另类 欧美 丝袜 | 亚洲精品一区二区三区中文字幕 | 亚洲91视频| 日韩欧美亚洲一区 | 亚洲欧美视频一区 | 三级黄色片在线 | 91香蕉视频在线观看 | 国产精品成人国产乱一区 | 欧美综合一区二区 | 国产一区二区三区高清 | 国产精品久久久亚洲 | 中文字幕在线一区二区三区 | 亚洲综合小视频 | 亚洲欧美一区二区三区在线 | 久久亚洲免费 | 免费久久99精品国产婷婷六月 | 91精品福利 | 欧美亚洲日本 | 国产亚洲精品91 | 亚洲精品av在线 | 伊人久久伊人 | 综合自拍 | 日韩欧美在线观看视频网站 | 爱操影视 | 亚洲视频国产视频 | 精品自拍视频在线观看 | 狠狠干天天干 |