Рубрики
Без рубрики

Аннотация @Запланирована на весну

Как использовать аннотацию @Scheduled весной для выполнения задач с фиксированной задержкой, с фиксированной скоростью или в соответствии с выражением cron.

Автор оригинала: Eugen Paraschiv.

1. Обзор

В этом уроке мы проиллюстрируем, как Spring @Scheduled аннотацию можно использовать для настройки и планирования задач.

Простые правила, которым мы должны следовать, чтобы аннотировать метод с помощью @Scheduled , следующие:

  • метод должен иметь тип void return
  • метод не должен принимать никаких параметров

Дальнейшее чтение:

Как сделать @Async весной

Руководство по планировщику задач Spring

Планирование весной с кварцем

2. Включите поддержку планирования

Чтобы включить поддержку задач планирования и аннотации @Scheduled весной, мы можем использовать аннотацию в стиле Java enable:

@Configuration
@EnableScheduling
public class SpringConfig {
    ...
}

И наоборот, мы можем сделать то же самое в XML:

3. Запланируйте задачу с фиксированной задержкой

Давайте начнем с настройки задачи для запуска после фиксированной задержки:

@Scheduled(fixedDelay = 1000)
public void scheduleFixedDelayTask() {
    System.out.println(
      "Fixed delay task - " + System.currentTimeMillis() / 1000);
}

В этом случае фиксируется продолжительность между окончанием последнего выполнения и началом следующего. Задача всегда ждет, пока предыдущая не будет завершена.

Этот параметр следует использовать, когда необходимо завершить предыдущее выполнение перед повторным запуском.

4. Запланируйте задачу с фиксированной скоростью

Теперь давайте выполним задачу с фиксированным интервалом времени:

@Scheduled(fixedRate = 1000)
public void scheduleFixedRateTask() {
    System.out.println(
      "Fixed rate task - " + System.currentTimeMillis() / 1000);
}

Этот параметр следует использовать, когда каждое выполнение задачи является независимым.

Обратите внимание, что запланированные задачи по умолчанию не выполняются параллельно. Поэтому , даже если мы использовали фиксированную ставку , следующая задача не будет вызвана до тех пор, пока не будет выполнена предыдущая.

Если мы хотим поддерживать параллельное поведение в запланированных задачах, нам необходимо добавить @Async аннотация:

@EnableAsync
public class ScheduledFixedRateExample {
    @Async
    @Scheduled(fixedRate = 1000)
    public void scheduleFixedRateTaskAsync() throws InterruptedException {
        System.out.println(
          "Fixed rate task async - " + System.currentTimeMillis() / 1000);
        Thread.sleep(2000);
    }

}

Теперь эта асинхронная задача будет вызываться каждую секунду, даже если предыдущая задача не выполнена.

5. Фиксированная ставка против Фиксированной задержки

Мы можем запустить запланированную задачу, используя аннотацию Spring @Scheduled , но, основываясь на свойствах фиксированной задержки и фиксированной скорости, характер выполнения меняется.

То фиксированная Задержка свойство гарантирует, что существует задержка n миллисекунда между временем завершения выполнения задачи и временем начала следующего выполнения задачи.

Это свойство особенно полезно, когда нам нужно убедиться, что все время выполняется только один экземпляр задачи. Для зависимых рабочих мест это очень полезно.

Свойство fixed Rate запускает запланированную задачу каждые n миллисекунды. Он не проверяет наличие каких-либо предыдущих выполнений задачи.

Это полезно, когда все выполнения задачи независимы. Если мы не ожидаем превышения размера памяти и пула потоков, фиксированная скорость должна быть очень удобной.

Хотя, если входящие задачи не заканчиваются быстро, вполне возможно, что они заканчиваются “Исключением из памяти”.

6. Запланируйте задачу С Начальной Задержкой

Далее давайте запланируем задачу с задержкой (в миллисекундах):

@Scheduled(fixedDelay = 1000, initialDelay = 1000)
public void scheduleFixedRateWithInitialDelayTask() {
 
    long now = System.currentTimeMillis() / 1000;
    System.out.println(
      "Fixed rate task with one second initial delay - " + now);
}

Обратите внимание, как в этом примере мы используем как фиксированную задержку , так и начальную задержку . Задача будет выполнена в первый раз после значения начальная задержка , и она будет продолжать выполняться в соответствии с fixedDelay .

Эта опция удобна, когда задача имеет настройку, которую необходимо выполнить.

7. Запланируйте задачу с помощью выражений Cron

Иногда задержек и скорости недостаточно, и нам нужна гибкость выражения cron для управления расписанием наших задач:

@Scheduled(cron = "0 15 10 15 * ?")
public void scheduleTaskUsingCronExpression() {
 
    long now = System.currentTimeMillis() / 1000;
    System.out.println(
      "schedule tasks using cron jobs - " + now);
}

Обратите внимание, что в этом примере мы планируем выполнение задачи в 10:15 утра 15-го числа каждого месяца.

По умолчанию Spring будет использовать локальный часовой пояс сервера для выражения cron. Однако мы можем использовать атрибут zone для изменения этого часового пояса :

@Scheduled(cron = "0 15 10 15 * ?", zone = "Europe/Paris")

При такой конфигурации Spring будет планировать запуск аннотированного метода в 10:15 утра 15-го числа каждого месяца по парижскому времени.

8. Параметризация расписания

Жесткое кодирование этих расписаний несложно, но обычно нам нужно иметь возможность управлять расписанием без перекомпиляции и повторного развертывания всего приложения.

Мы будем использовать выражения Spring для экстернализации конфигурации задач и сохраним их в файлах свойств.

A фиксированная задержка задача:

@Scheduled(fixedDelayString = "${fixedDelay.in.milliseconds}")

A фиксированная ставка задача:

@Scheduled(fixedRateString = "${fixedRate.in.milliseconds}")

A cron задача на основе выражений:

@Scheduled(cron = "${cron.expression}")

9. Настройка Запланированных Задач С Помощью XML

Spring также предоставляет XML – способ настройки запланированных задач. Вот конфигурация XML для их настройки:






    
    
    

10. Динамическая настройка задержки или скорости во время выполнения

Обычно все свойства аннотации @Scheduled разрешаются и инициализируются только один раз при запуске контекста Spring.

Поэтому изменение фиксированной задержки или фиксированной скорости значений во время выполнения невозможно, когда мы используем @Scheduled аннотацию весной .

Однако есть обходной путь. Использование Spring’s SchedulingConfigurer предоставляет более настраиваемый способ дать нам возможность динамически устанавливать задержку или скорость .

Давайте создадим конфигурацию Spring, Dynamic Scheduling Config и реализуем интерфейс SchedulingConfigurer :

@Configuration
@EnableScheduling
public class DynamicSchedulingConfig implements SchedulingConfigurer {

    @Autowired
    private TickService tickService;

    @Bean
    public Executor taskExecutor() {
        return Executors.newSingleThreadScheduledExecutor();
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
        taskRegistrar.addTriggerTask(
          new Runnable() {
              @Override
              public void run() {
                  tickService.tick();
              }
          },
          new Trigger() {
              @Override
              public Date nextExecutionTime(TriggerContext context) {
                  Optional lastCompletionTime =
                    Optional.ofNullable(context.lastCompletionTime());
                  Instant nextExecutionTime =
                    lastCompletionTime.orElseGet(Date::new).toInstant()
                      .plusMillis(tickService.getDelay());
                  return Date.from(nextExecutionTime);
              }
          }
        );
    }

}

Как мы заметили, с помощью метода ScheduledTaskRegistrar#add Trigger Task мы можем добавить Выполняемую задачу и Триггер реализацию для пересчета nextExecutionTime после окончания каждого выполнения.

Кроме того, мы аннотируем нашу конфигурацию динамического планирования с помощью @EnableScheduling , чтобы заставить планирование работать.

В результате мы запланировали запуск метода Tick Service#tick после каждой задержки, которая динамически определяется во время выполнения методом getDelay .

11. Заключение

В этой статье мы обсудили, как настроить и использовать @Scheduled аннотацию .

Мы рассмотрели процесс включения планирования и различные способы настройки шаблонов задач планирования. Мы также показали обходной путь для динамической настройки задержки и скорости.

Примеры, показанные выше, можно найти на GitHub .