Penjadualan pada musim bunga dengan Quartz

1. Gambaran keseluruhan

Dalam tutorial ini kita akan membina Penjadual sederhana pada Musim Bunga dengan Quartz .

Kami akan memulakan dengan tujuan sederhana - untuk mengkonfigurasi pekerjaan berjadual baru dengan mudah.

1.1. Komponen Utama API Kuarsa

Quartz mempunyai seni bina modular. Ia terdiri daripada beberapa komponen asas yang dapat digabungkan mengikut keperluan. Dalam tutorial ini, kita akan memfokuskan pada perkara yang umum untuk setiap pekerjaan: Job , JobDetail , Trigger dan Penjadual .

Walaupun kami akan menggunakan Spring untuk menguruskan aplikasi, setiap komponen individu dapat dikonfigurasi dengan dua cara: cara Quartz atau cara Spring (menggunakan kelas kemudahannya).

Kami akan merangkumi keduanya sejauh mungkin demi kelengkapan, tetapi kedua-duanya boleh diterima pakai. Mari mula membina, satu komponen pada satu masa.

2. Job and JobDetail

2.1. Pekerjaan

API menyediakan antara muka Pekerjaan yang hanya mempunyai satu kaedah - jalankan. Ia mesti dilaksanakan oleh kelas yang mengandungi kerja sebenar yang harus dilakukan, iaitu tugas. Apabila pemicu pekerjaan diaktifkan , penjadual menggunakan kaedah pelaksanaan , meneruskannya sebagai objek JobExecutionContext .

The JobExecutionContext menyediakan contoh kerja dengan maklumat tentang persekitaran runtime, termasuk pemegang untuk penjadual, pemegang untuk picu, dan tugas JobDetail objek.

Dalam contoh ringkas ini - tugas menyerahkan tugas ke kelas perkhidmatan:

@Component public class SampleJob implements Job { @Autowired private SampleJobService jobService; public void execute(JobExecutionContext context) throws JobExecutionException { jobService.executeSampleJob(); } } 

2.2. Maklumat Pekerjaan

Walaupun pekerjaan itu adalah tenaga kerja, Quartz tidak menyimpan contoh sebenar kelas pekerjaan. Sebagai gantinya, kita dapat menentukan contoh Job menggunakan kelas JobDetail . Kelas pekerjaan mesti diberikan kepada JobDetail sehingga mengetahui jenis pekerjaan yang akan dilaksanakan.

2.3. Pembangun Kerja Kuarza

Quartz JobBuilder menyediakan API gaya pembina untuk membina entiti 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's JobDetailFactoryBean menyediakan penggunaan gaya kacang untuk mengkonfigurasi contoh JobDetail . Ia menggunakan nama kacang kacang sebagai nama pekerjaan, jika tidak dinyatakan:

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

Contoh JobDetail baru dibuat untuk setiap pelaksanaan pekerjaan. The JobDetail ini menyampaikan objek sifat terperinci kerja. Setelah pelaksanaan selesai, rujukan ke contoh akan dihapus.

3. Pencetus

A Trigger adalah mekanisme untuk menjadualkan pekerjaan , iaitu Trigger contoh "kebakaran" pelaksanaan pekerjaan. Terdapat pemisahan tanggungjawab yang jelas antara Pekerjaan (konsep tugas) dan Pencetus (mekanisme penjadualan).

Selain Job , pemicu juga memerlukan jenis yang dapat dipilih berdasarkan keperluan penjadualan.

Katakanlah, kami ingin menjadualkan tugas kami untuk dilaksanakan sekali setiap jam, tanpa had - kami boleh menggunakan TriggerBuilder Quartz atau SimpleTriggerFactoryBean Spring untuk melakukannya.

3.1. Pembangun Kuarsa

TriggerBuilder adalah API gaya pembina untuk membina entiti Pencetus :

@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. Spring SimpleTriggerFactoryBean

SimpleTriggerFactoryBean menyediakan penggunaan gaya kacang untuk mengkonfigurasi SimpleTrigger . Ia menggunakan nama kacang musim bunga sebagai nama pencetus dan lalai untuk pengulangan tanpa batas, jika tidak dinyatakan sebaliknya:

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

4. Mengkonfigurasi JobStore

JobStore menyediakan mekanisme penyimpanan untuk Pekerjaan dan Pencetus , dan bertanggung jawab untuk menjaga semua data yang relevan dengan penjadwalan pekerjaan. API menyokong kedai dalam memori dan berterusan .

4.1. Kedai Kerja Dalam Memori

Sebagai contoh, kami akan menggunakan RAMJobStore dalam memori yang menawarkan prestasi pantas dan konfigurasi mudah melalui quartz.properties :

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

Kelemahan jelas dari RAMJobStore adalah sifatnya yang mudah berubah . Semua maklumat penjadualan hilang di antara penutupan. Sekiranya definisi dan jadual kerja mesti disimpan antara penutupan, JDBCJobStore yang berterusan mesti digunakan sebagai gantinya.

Untuk mengaktifkan JobStore dalam memori pada musim bunga , kami menetapkan harta tanah ini dalam aplikasi kami .

spring.quartz.job-store-type=memory

4.2. Kedai Kerja JDBC

There are two types of JDBCJobStore: JobStoreTX and JobStoreCMT. They both do the same job of storing scheduling information in a database.

The difference between the two is how they manage the transactions that commit the data. The JobStoreCMT type requires an application transaction to store data, whereas the JobStoreTX type starts and manages its own transactions.

There are several properties to set for a JDBCJobStore. At a minimum, we must specify the type of JDBCJobStore, the data source, and the database driver class. There are driver classes for most databases, but StdJDBCDelegate covers most cases:

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

Setting up a JDBC JobStore in Spring takes a few steps. Firstly, we set the store type in our application.properties:

spring.quartz.job-store-type=jdbc

Next, we need to enable auto-configuration and give Spring the data source needed by the Quartz scheduler. The @QuartzDataSource annotation does the hard work in configuring and initializing the Quartz database for us:

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

5. Scheduler

The Scheduler interface is the main API for interfacing with the job scheduler.

A Scheduler can be instantiated with a SchedulerFactory. Once created, Jobs and Triggers can be registered with it. Initially, the Scheduler is in “stand-by” mode, and its start method must be invoked to start the threads that fire the execution of jobs.

5.1. Quartz StdSchedulerFactory

By simply invoking the getScheduler method on the StdSchedulerFactory, we can instantiate the Scheduler, initialize it (with the configured JobStore and ThreadPool), and return a handle to its 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. Spring SchedulerFactoryBean

Spring's SchedulerFactoryBean provides bean-style usage for configuring a Scheduler, manages its life-cycle within the application context, and exposes the Scheduler as a bean for dependency injection:

@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. Configuring SpringBeanJobFactory

The SpringBeanJobFactory provides support for injecting the scheduler context, job data map, and trigger data entries as properties into the job bean while creating an instance.

However, it lacks support for injecting bean references from the application context. Thanks to the author of this blog post, we can add auto-wiring support to SpringBeanJobFactory like so:

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

6. Conclusion

That's all. We have just built our first basic scheduler using the Quartz API as well as Spring's convenience classes.

The key takeaway from this tutorial is that we were able to configure a job with just a few lines of code and without using any XML-based configuration.

The complete source code for the example is available in this github project. It is a Maven project which can be imported and run as-is. The default setting uses Spring's convenience classes, which can be easily switched to Quartz API with a run-time parameter (refer to the README.md in the repository).