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

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

1. обзор

В этом руководстве мы построим простойScheduler in Spring with Quartz.

Мы начнем с простой цели - легко настроить новое запланированное задание.

1.1. Ключевые компоненты Quartz API

Кварц имеет модульную архитектуру. Он состоит из нескольких основных компонентов, которые можно комбинировать по мере необходимости. В этом руководстве мы сосредоточимся на тех, которые являются общими для каждого задания:Job,JobDetail,Trigger иScheduler.

Хотя мы будем использовать Spring для управления приложением, каждый отдельный компонент можно настроить двумя способами: способомQuartz или способомSpring(используя его удобные классы).

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

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

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

Краткое и практическое руководство по планированию в Spring с помощью Task Scheduler

Read more

Планирование в Java EE

Демонстрация того, как планировать задачи в Java EE, используя аннотацию @Schedule и службу таймера.

Read more

Введение в слюни

Узнайте, как использовать Drools в качестве системы управления бизнес-правилами (BRMS).

Read more

2. Job иJobDetail

2.1. Jobс

API предоставляет интерфейсJob, имеющий только один метод -execute.. Он должен быть реализован классом, который содержит фактическую работу, которую необходимо выполнить, т.е. задание. Когда срабатывает триггер задания, планировщик вызывает методexecute, передавая ему объектJobExecutionContext.

JobExecutionContext предоставляет экземпляру задания информацию о его среде выполнения, включая дескриптор планировщика, дескриптор триггера и объект заданияJobDetail.

В этом быстром примере - задание делегирует задачу классу обслуживания: __

@Component
public class SampleJob implements Job {

    @Autowired
    private SampleJobService jobService;

    public void execute(JobExecutionContext context) throws JobExecutionException {
        jobService.executeSampleJob();
    }
}

2.2. JobDetailс

В то время как задание является рабочей лошадкой, Quartz не хранит фактический экземпляр класса задания. Вместо этого мы можем определить экземплярJob, используя классJobDetail. Класс задания должен быть предоставленJobDetail, чтобы он зналtype задания, которое должно быть выполнено.

2.3. КварцJobBuilder

QuartzJobBuilder предоставляет API-интерфейс в стиле сборщика для создания объектовJobDetail.

@Bean
public JobDetail jobDetail() {
    return JobBuilder.newJob().ofType(SampleJob.class)
      .storeDurably()
      .withIdentity("Qrtz_Job_Detail")
      .withDescription("Invoke Sample Job service...")
      .build();
}

2.4. ПружинаJobDetailFactoryBean

JobDetailFactoryBean Spring обеспечивает использование стиля bean-компонента для настройки экземпляровJobDetail. В качестве имени задания используется имя bean-компонента Spring, если не указано иное:

@Bean
public JobDetailFactoryBean jobDetail() {
    JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
    jobDetailFactory.setJobClass(SampleJob.class);
    jobDetailFactory.setDescription("Invoke Sample Job service...");
    jobDetailFactory.setDurability(true);
    return jobDetailFactory;
}

Новый экземплярJobDetail создается для каждого выполнения задания. ОбъектJobDetail передает подробные свойства задания. По завершении выполнения ссылки на экземпляр удаляются.

3. Спусковой крючок

ATrigger - это механизм для планирования aJob, т.е. ЭкземплярTrigger «запускает» выполнение задания. Существует четкое разделение ответственности междуJob (понятие задачи) иTrigger (механизм планирования).

В дополнение кJob триггеру также требуетсяtype, который можно выбрать на основе требований планирования.

Допустим, мы хотим запланировать выполнение нашей задачиonce every hour, на неопределенное время - для этого мы можем использовать QuartzTriggerBuilder или SpringSimpleTriggerFactoryBean.

3.1. КварцTriggerBuilder

TriggerBuilder - это API в стиле построителя для создания объектаTrigger:

@Bean
public Trigger trigger(JobDetail job) {
    return TriggerBuilder.newTrigger().forJob(job)
      .withIdentity("Qrtz_Trigger")
      .withDescription("Sample trigger")
      .withSchedule(simpleSchedule().repeatForever().withIntervalInHours(1))
      .build();
}

3.2. ПружинаSimpleTriggerFactoryBean

SimpleTriggerFactoryBean обеспечивает использование стиля компонента для настройкиSimpleTrigger. Он использует имя bean-компонента Spring в качестве имени триггера и по умолчанию использует неопределенное повторение, если не указано иное:

@Bean
public SimpleTriggerFactoryBean trigger(JobDetail job) {
    SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
    trigger.setJobDetail(job);
    trigger.setRepeatInterval(3600000);
    trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
    return trigger;
}

4. НастройкаJobStore

JobStore обеспечивает механизм хранения дляJob иTrigger и отвечает за поддержание всех данных, относящихся к планировщику заданий. API поддерживает как хранилищаin-memory, так иpersistent.

4.1. В памятиJobStoreс

В качестве примера мы будем использовать in-memoryRAMJobStore, который предлагает невероятно высокую производительность и простую настройку черезquartz.properties:

org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore

Очевидный недостатокRAMJobStore заключается в том, что по своей природе онvolatile. Вся информация о расписании теряется между выключениями. Если определения заданий и расписания должны сохраняться между выключениями, вместо этого следует использовать постоянныйJDBCJobStore. Чтобы включитьJobStore в памяти в Spring,, мы устанавливаем это свойство в нашемapplication.properties:

spring.quartz.job-store-type=memory

4.2. JDBCJobStore

Существует два типаJDBCJobStore:JobStoreTX иJobStoreCMT. Они оба выполняют одинаковую работу по сохранению информации о расписании в базе данных.

Разница между ними заключается в том, как они управляют транзакциями, которые передают данные. ТипJobStoreCMT требует транзакции приложения для хранения данных, тогда как типJobStoreTX запускает и управляет своими собственными транзакциями.

Есть несколько свойств, которые можно установить дляJDBCJobStore. Как минимум, мы должны указать типJDBCJobStore, источник данных и класс драйвера базы данных. Существуют классы драйверов для большинства баз данных, ноStdJDBCDelegate охватывает большинство случаев:

org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.dataSource=quartzDataSource

Для настройки JDBCJobStore в Spring требуется несколько шагов. Во-первых, мы устанавливаем тип магазина в нашемapplication.properties:

spring.quartz.job-store-type=jdbc

Далее нам нужно включить автоконфигурацию и предоставить Spring источник данных, необходимый для планировщика Quartz. Аннотация@QuartzDataSource выполняет тяжелую работу по настройке и инициализации базы данных Quartz за нас:

@Configuration
@EnableAutoConfiguration
public class SpringQrtzScheduler {

    @Bean
    @QuartzDataSource
    public DataSource quartzDataSource() {
        return DataSourceBuilder.create().build();
    }
}

5. Schedulerс

ИнтерфейсScheduler является основным API для взаимодействия с планировщиком заданий.

Scheduler можно создать с помощьюSchedulerFactory.. После созданияJobs иTriggers могут быть зарегистрированы с ним. ПервоначальноScheduler находится в режиме ожидания, и его методstart должен быть вызван для запуска потоков, которые запускают выполнение заданий.

5.1. КварцStdSchedulerFactory

Просто вызвав методgetScheduler наStdSchedulerFactory, мы можем создать экземплярScheduler, инициализировать его (с настроеннымиJobStore иThreadPool) и вернуть дескриптор своего API:

@Bean
public Scheduler scheduler(Trigger trigger, JobDetail job, SchedulerFactoryBean factory)
  throws SchedulerException {
    Scheduler scheduler = factory.getScheduler();
    scheduler.scheduleJob(job, trigger);
    scheduler.start();
    return scheduler;
}

5.2. ПружинаSchedulerFactoryBean

SpringSchedulerFactoryBean обеспечивает использование стиля bean-компонента для настройкиScheduler, управляет его жизненным циклом в контексте приложения и предоставляетScheduler как bean-компонент для внедрения зависимостей:

@Bean
public SchedulerFactoryBean scheduler(Trigger trigger, JobDetail job, DataSource quartzDataSource) {
    SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();
    schedulerFactory.setConfigLocation(new ClassPathResource("quartz.properties"));

    schedulerFactory.setJobFactory(springBeanJobFactory());
    schedulerFactory.setJobDetails(job);
    schedulerFactory.setTriggers(trigger);
    schedulerFactory.setDataSource(quartzDataSource);
    return schedulerFactory;
}

5.3. НастройкаSpringBeanJobFactory

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

Однако в нем отсутствует поддержка внедрения ссылок на bean-компоненты изapplication context. Благодаря авторуthis blog post, мы можем добавить поддержкуauto-wiring кSpringBeanJobFactory следующим образом:

@Bean
public SpringBeanJobFactory springBeanJobFactory() {
    AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    return jobFactory;
}

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

Вот и все. Мы только что создали наш первый базовый планировщик, используя Quartz API, а также удобные классы Spring.

Ключевым выводом этого учебного пособия является то, что мы смогли настроить работу всего за несколько строк кода и без использования какой-либо конфигурации на основе XML.

Полныйsource code для примера доступен вthis github project. Это проект Maven, который можно импортировать и запускать как есть. По умолчанию используются удобные классы Spring, которые можно легко переключить на Quartz API с помощью параметра времени выполнения (см. README.md в репозитории).