Spring Boot, третья серия Spring @EnableScheduling, сводка использования временных задач

Spring Boot

1. Принцип

1.1 TaskScheduler

TaskScheduler — это ключевой класс пула потоков, используемый временными задачами Spring.

public interface TaskScheduler {
    // 通过Trigger执行任务
    ScheduledFuture schedule(Runnable task, Trigger trigger);
// 指定时间执行任务
    ScheduledFuture schedule(Runnable task, Date startTime);
// 指定在指定时间后,循环周期执行任务
    ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);
    //  循环周期执行任务
    ScheduledFuture scheduleAtFixedRate(Runnable task, long period);
    // 延迟N时间,在指定日期执行
    ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
    ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}

TaskScheduler имеет две реализации:
- TimerManagerTaskScheduler: используйте внешние объекты для управления пулами потоков, такие как CommonJ TimerManager, подходящие для нескольких процессов для совместного использования пулов потоков.
- ThreadPoolTaskScheduler: рекомендуется использовать этот объект, если пул потоков управляется только в том же процессе. Он фактически управляет пулом потоков, используя собственный ScheduledExecutorService Java.

1.2 Trigger

Триггер — это ключевой класс для настройки временной задачи, время следующего выполнения метода конфигурации.

public interface Trigger {
    Date nextExecutionTime(TriggerContext triggerContext);
}

Параметр TriggerContext в методе инкапсулирует время последнего выполнения задачи и время последнего выполнения.

public interface TriggerContext {
    Date lastScheduledExecutionTime();
    Date lastActualExecutionTime();
    Date lastCompletionTime();
}

Реализация TriggerContext по умолчанию — SimpleTriggerContext, а реализация исходного кода очень проста.

Класс для реализации триггера:
- crontrigger: Использование времени выполнения задачи определения выражения cron
Такие как:scheduler.schedule(task, new CronTrigger("0 15 9-17 * * MON-FRI"));
- PeriodicTrigger: через «фиксированный период», «начальное значение задержки», «логическое значение, чтобы указать, должен ли период интерпретироваться как параметры с фиксированной скоростью или с фиксированной задержкой 3 настраивают время выполнения задачи

2. Запланированный метод @Scheduled

Определите запланированные задачи через @Scheduled

  1. fixedDelay: после выполнения каждого метода подождите, пока Nms выполнит этот метод.

        /**
         * 每次方法执行完毕后,等待5s再执行此方法。
         *  同时只能有个线程运行此方法
         */
        @Scheduled(fixedDelay=5000)
        public void fixedDelay() {
            try {
                // 执行方法需要10s
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
            }
            log.info("fixedDelay--");
        }

    Примечание. Возвращаемое значение метода синхронизации может быть только пустым и не может иметь входящие параметры.

  2. fixedRate: этот метод вызывается каждые 5 секунд, независимо от того, был ли выполнен предыдущий метод или нет.

    /**
         * 每隔5s调用一次此方法,无论之前的方法是否执行完毕
         *  同时可能有N个线程执行此方法
         *  
         */
        @Scheduled(fixedRate=5000)
        public void fixedRate() {
            try {
                // 执行方法需要10s
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
            }
            log.info("fixedRate--");
        }
  3. initialDelay: время ожидания перед вызовом этого метода в первый раз

    /***
         * initialDelay: 第一次调用此方法前的等待时间
         * 
         */ 
        @Scheduled(initialDelay=1000, fixedRate=5000)
        public void initialDelayAndfixedRate() {
            log.info("initialDelayAndfixedRate--");
        }
  4. cron: настроить значения через cron

        /**
         * 支持cron语法:
         * 每个参数的意义分别是: second, minute, hour, day of month, month, day of week
         * 
         * 如下:周一至周五,每隔5s执行一次方法
         */
        @Scheduled(cron="*/5 * * * * SUN-MON")
        public void cron() {
            log.info("cron--");
        }
  5. Полный демо-код

    /**
     * 定时类
     *  不同异步方法:定时方法只能返回void且不能接受任务参数 
     * 
     * @author hry
     *
     */
    @Component
    public class ScheduleDemo {
        private static final Logger log = Logger.getLogger(ScheduleDemo.class);
    
        /**
         * 每次方法执行完毕后,等待5s再执行此方法。
         *  同时只能有个线程运行此方法
         */
        @Scheduled(fixedDelay=5000)
        public void fixedDelay() {
            try {
                // 执行方法需要10s
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
            }
            log.info("fixedDelay--");
        }
    
        /**
         * 每隔5s调用一次此方法,无论之前的方法是否执行完毕
         *  同时可能有N个线程执行此方法
         *  
         */
        @Scheduled(fixedRate=5000)
        public void fixedRate() {
            try {
                // 执行方法需要10s
                Thread.sleep(1000 * 10);
            } catch (InterruptedException e) {
            }
            log.info("fixedRate--");
        }
    
        /***
         * initialDelay: 第一次调用此方法前的等待时间
         * 
         */ 
        @Scheduled(initialDelay=1000, fixedRate=5000)
        public void initialDelayAndfixedRate() {
            log.info("initialDelayAndfixedRate--");
        }
    
        /**
         * 支持cron语法:
         * 每个参数的意义分别是: second, minute, hour, day of month, month, day of week
         * 
         * 如下:周一至周五,每隔5s执行一次方法
         */
        @Scheduled(cron="*/5 * * * * SUN-MON")
        public void cron() {
            log.info("cron--");
        }
    }

3. Способ запуска метода синхронизации

Существуют следующие способы запуска запланированной задачи
1. Аннотация
Запускать запланированные задачи с помощью @EnableScheduling

    ```
        @SpringBootApplication
        @EnableScheduling // 启动定时任务
        public class ScheduleApplicationWithAnnotation {
            private static final Logger log = LoggerFactory.getLogger(ScheduleApplicationWithAnnotation.class);

            /**
             * 自定义定时任务线程池
             *  如果没有,则使用默认定时任务池
             * @return
             */
            @Bean(destroyMethod="shutdown")
            public Executor taskExecutor() {
                return  new ScheduledThreadPoolExecutor(10, new ThreadFactory() {
                    private AtomicInteger max = new AtomicInteger(0);
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, "mySchedulAnno-" + max.incrementAndGet());
                    }
                });
            }

            public static void main(String[] args) {
                log.info("Start ScheduleApplicationWithAnnotation.. ");
                SpringApplication.run(ScheduleApplicationWithAnnotation.class, args);
            }
        }

    ```

2. XML-конфигурация
Задача: управляемая аннотациями эквивалентна @EnableScheduling, которая запускает запланированную задачу.
задача: управляемая аннотациями эквивалентна @EnableScheduling, планировщик указывает пул потоков
id указывает префикс имени потока, сгенерированного пулом потоков

<task:annotation-driven scheduler="myScheduler"/>
<task:scheduler id="myScheduler" pool-size="10" />

```
/**
 * 通过XML启动异步方法
 * @author hry
 * 
 */
@SpringBootApplication
@ImportResource("classpath:/schedule/spring_schedule.xml")
public class ScheduleApplicationWithXML {
    private static final Logger log = LoggerFactory.getLogger(ScheduleApplicationWithXML.class);

    public static void main(String[] args) {
        log.info("Start ScheduleApplicationWithXML.. ");
        SpringApplication.run(ScheduleApplicationWithXML.class, args);
    }
}
```

4. Пользовательский пул потоков конфигурации

通过实现SchedulingConfigurer 对定时任务线程池进行更细化的配置
```
/**
 * 通过实现SchedulingConfigurer对定时任务线程池进行更细致配置
 * @author hry
 *
 */
@Component
@Configuration
public class MySchedulingConfigurer implements SchedulingConfigurer  {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return  new ScheduledThreadPoolExecutor(10, new ThreadFactory() {
            private AtomicInteger max = new AtomicInteger(0);
            @Override
            public Thread newThread(Runnable r) {
                return new Thread(r, "myScheConfig-" + max.incrementAndGet());
            }
        });
    }
}

```

 通过@EnableScheduling启动定时方法
```
/**
 * 通过@EnableScheduling启动定时方法
 * 配置
 * 
 * @author hry
 * 
 */
@SpringBootApplication
@EnableScheduling // 启动定时任务
public class ScheduleApplicationWithSchedulingConfigurer {
    private static final Logger log = LoggerFactory.getLogger(ScheduleApplicationWithSchedulingConfigurer.class);

    public static void main(String[] args) {
        log.info("Start ScheduleApplicationWithSchedulingConfigurer.. ");
        SpringApplication.run(ScheduleApplicationWithSchedulingConfigurer.class, args);
    }
}
```

5. Код

github