1. Обзор
В этом уроке мы построим простой планировщик весной с помощью Quartz .
Мы начнем с простой цели – легко настроить новое запланированное задание.
1.1. Ключевые компоненты API Quartz
Кварц имеет модульную архитектуру. Он состоит из нескольких основных компонентов, которые могут быть объединены по мере необходимости. В этом уроке мы сосредоточимся на тех, которые являются общими для каждого задания: Задание , Детали задания , Триггер и | Планировщик .
Хотя мы будем использовать Spring для управления приложением, каждый отдельный компонент может быть настроен двумя способами: Quartz way или Spring way (используя свои классы удобства).
Мы рассмотрим оба варианта, насколько это возможно, для полноты картины, но любой из них может быть принят. Давайте начнем строить, по одному компоненту за раз.
Дальнейшее чтение:
Руководство по Весеннему планировщику задач
Планирование в Джакарте EE
Введение в слюни
2. Работа и детали работы
2.1. Работа
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 . Класс задания должен быть предоставлен в Сведения о задании , чтобы он знал тип выполняемого задания.
2.3. Кварцевый ДжоБбилдер
Quartz JobBuilder предоставляет 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. Spring JobDetailFactoryBean
Spring JobDetailFactoryBean обеспечивает использование бобового стиля для настройки экземпляров JobDetail . Он использует имя компонента Spring в качестве имени задания, если не указано иное:
@Bean public JobDetailFactoryBean jobDetail() { JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); jobDetailFactory.setJobClass(SampleJob.class); jobDetailFactory.setDescription("Invoke Sample Job service..."); jobDetailFactory.setDurability(true); return jobDetailFactory; }
Для каждого выполнения задания создается новый экземпляр Job Detail . Объект JobDetail передает подробные свойства задания. После завершения выполнения ссылки на экземпляр удаляются.
3. Триггер
/| Триггер – это механизм планирования Задания , т. Е. экземпляр триггера “запускает” выполнение задания. Существует четкое разделение обязанностей между Заданием (понятие задачи) и Триггером (механизм планирования).
В дополнение к Заданию триггеру также требуется тип , который может быть выбран на основе требований планирования.
Допустим, мы хотим запланировать выполнение нашей задачи один раз в час, на неопределенный срок – для этого мы можем использовать Quartz TriggerBuilder или Spring SimpleTriggerFactoryBean .
3.1. Кварцевый триггер
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 обеспечивает использование бобового стиля для настройки Простого триггера . Он использует имя компонента 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. Настройка хранилища заданий
Хранилище заданий обеспечивает механизм хранения для Задания и Триггера и отвечает за сохранение всех данных , относящихся к планировщику заданий. API поддерживает как в памяти , так и постоянные хранилища.
4.1. Магазин заданий в памяти
Например, мы будем использовать встроенный в память RAMJobStore , который предлагает невероятно быструю производительность и простую конфигурацию через quartz.properties :
org.quartz.jobStore.class=org.quartz.simpl.RAMJobStore
Очевидным недостатком RAMJobStore является то, что он изменчив по своей природе. Вся информация о расписании теряется между остановками. Если определения заданий и расписания должны сохраняться между остановками, вместо этого следует использовать постоянный JDBCJobStore . Чтобы включить в памяти Хранилище заданий весной , мы задаем это свойство в нашем application.properties :
spring.quartz.job-store-type=memory
4.2. JDBC JobStore
Существует два типа 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
Настройка JDBC JobStore весной занимает несколько шагов. Во-первых, мы устанавливаем тип магазина в нашем 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 является основным API для взаимодействия с планировщиком заданий.
Scheduler может быть создан с помощью SchedulerFactory. После создания Задание s и Триггер s могут быть зарегистрированы в нем. Изначально планировщик находится в режиме “ожидания”, и его метод 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. Весенний планировщик FactoryBean
Spring SchedulerFactoryBean обеспечивает использование в стиле бобов для настройки Планировщика , управляет его жизненным циклом в контексте приложения и предоставляет Планировщик в качестве боба для внедрения зависимостей:
@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 обеспечивает поддержку ввода контекста планировщика, jobdatamap и записей данных триггера в качестве свойств в компонент задания при создании экземпляра.
Однако в нем отсутствует поддержка для введения ссылок на бобы из контекста приложения . Благодаря автору этого сообщения в блоге , мы можем добавить автоматическую проводку поддержку SpringBeanJobFactory вот так:
@Bean public SpringBeanJobFactory springBeanJobFactory() { AutoWiringSpringBeanJobFactory jobFactory = new AutoWiringSpringBeanJobFactory(); jobFactory.setApplicationContext(applicationContext); return jobFactory; }
6. Заключение
Это все. Мы только что создали наш первый базовый планировщик, используя API Quartz, а также классы удобства Spring.
Ключевым выводом из этого руководства является то, что мы смогли настроить задание всего с помощью нескольких строк кода и без использования какой-либо конфигурации на основе XML.
Полный исходный код для примера доступен в этом проекте github . Это проект Maven, который можно импортировать и запускать как есть. Настройка по умолчанию использует классы удобства Spring, которые можно легко переключить на Quartz API с параметром времени выполнения (см. README.md в репозитории).