Pengantar Kuarsa

1. Ikhtisar

Quartz adalah kerangka kerja penjadwalan pekerjaan open source yang seluruhnya ditulis di Java dan dirancang untuk digunakan di aplikasi J2SE dan J2EE . Ini menawarkan fleksibilitas luar biasa tanpa mengorbankan kesederhanaan.

Anda dapat membuat jadwal yang rumit untuk melaksanakan pekerjaan apa pun. Contohnya adalah misalnya tugas-tugas yang dijalankan setiap hari, setiap hari Jumat pukul 19.30 atau hanya pada hari terakhir setiap bulan.

Di artikel ini, kita akan melihat elemen untuk membuat pekerjaan dengan Quartz API. Untuk pengenalan yang dikombinasikan dengan Pegas, kami merekomendasikan Penjadwalan di Musim Semi dengan Quartz.

2. Ketergantungan Maven

Kita perlu menambahkan ketergantungan berikut ke pom.xml:

 org.quartz-scheduler quartz 2.3.0 

Versi terbaru dapat ditemukan di repositori Maven Central.

3. API Kuarsa

Inti dari framework ini adalah Scheduler . Ini bertanggung jawab untuk mengelola lingkungan runtime untuk aplikasi kita.

Untuk memastikan skalabilitas, Quartz didasarkan pada arsitektur multi-threaded. Saat dimulai, kerangka kerja akan menginisialisasi sekumpulan utas pekerja yang digunakan oleh Penjadwal untuk menjalankan Pekerjaan .

Beginilah cara framework dapat menjalankan banyak Pekerjaan secara bersamaan. Ini juga bergantung pada sekumpulan komponen manajemen ThreadPool yang digabungkan secara longgar untuk mengelola lingkungan thread.

Antarmuka utama API adalah:

  • Scheduler - API utama untuk berinteraksi dengan penjadwal framework
  • Pekerjaan - antarmuka yang akan diimplementasikan oleh komponen yang ingin kita jalankan
  • JobDetail - digunakan untuk mendefinisikan contoh Job s
  • Pemicu - komponen yang menentukan jadwal yang di atasnya diberikan Kerja akan dilakukan
  • JobBuilder - digunakan untuk membuat instance JobDetail , yang menentukan instance Pekerjaan
  • TriggerBuilder - digunakan untuk membuat instance Trigger

Mari kita lihat masing-masing komponen itu.

4. Penjadwal

Sebelum kita dapat menggunakan Scheduler , itu perlu dibuat instance-nya. Untuk melakukan ini, kita dapat menggunakan SchedulerFactory pabrik :

SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler();

Sebuah Scheduler ‘s siklus hidup dibatasi oleh penciptaan, melalui SchedulerFactory dan panggilan untuk nya shutdown () metode. Setelah dibuat, antarmuka Penjadwal dapat digunakan untuk menambah, menghapus, dan mencantumkan Pekerjaan dan Pemicu , dan melakukan operasi terkait penjadwalan lainnya (seperti menjeda pemicu).

Namun, yang Scheduler tidak akan bertindak pada setiap pemicu sampai telah dimulai dengan start () metode :

scheduler.start();

5. Pekerjaan

Sebuah Job adalah sebuah kelas yang mengimplementasikan dalam Job antarmuka. Ini hanya memiliki satu metode sederhana:

public class SimpleJob implements Job { public void execute(JobExecutionContext arg0) throws JobExecutionException { System.out.println("This is a quartz job!"); } }

Saat pemicu Job diaktifkan, metode execute () akan dipanggil oleh salah satu thread pekerja penjadwal.

The JobExecutionContext objek yang dilewatkan ke metode ini memberikan contoh pekerjaan, dengan informasi tentang lingkungan runtime, sebuah pegangan ke Scheduler yang dieksekusi itu, pegangan ke Pemicu yang memicu eksekusi, pekerjaan ini JobDetail objek, dan beberapa item lainnya .

The JobDetail objek dibuat oleh klien Quartz pada saat Job ditambahkan ke Scheduler. Ini pada dasarnya adalah definisi contoh pekerjaan :

JobDetail job = JobBuilder.newJob(SimpleJob.class) .withIdentity("myJob", "group1") .build();

Objek ini mungkin juga berisi berbagai pengaturan properti untuk Job , serta JobDataMap , yang dapat digunakan untuk menyimpan informasi status untuk instance tertentu dari kelas pekerjaan kita.

5.1. JobDataMap

The JobDataMap digunakan untuk menyimpan jumlah data objek yang kita ingin membuat tersedia untuk contoh pekerjaan ketika dijalankan. JobDataMap adalah implementasi antarmuka Java Map dan memiliki beberapa metode praktis tambahan untuk menyimpan dan mengambil data tipe primitif.

Berikut adalah contoh memasukkan data ke dalam JobDataMap saat membuat JobDetail , sebelum menambahkan pekerjaan ke penjadwal:

JobDetail job = newJob(SimpleJob.class) .withIdentity("myJob", "group1") .usingJobData("jobSays", "Hello World!") .usingJobData("myFloatValue", 3.141f) .build();

Dan berikut adalah contoh cara mengakses data ini selama eksekusi pekerjaan:

public class SimpleJob implements Job { public void execute(JobExecutionContext context) throws JobExecutionException { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); String jobSays = dataMap.getString("jobSays"); float myFloatValue = dataMap.getFloat("myFloatValue"); System.out.println("Job says: " + jobSays + ", and val is: " + myFloatValue); } }

Contoh di atas akan mencetak "Job said Hello World !, dan val adalah 3.141".

Kami juga dapat menambahkan metode penyetel ke kelas pekerjaan kami yang sesuai dengan nama kunci di JobDataMap.

Jika kita melakukan ini, implementasi JobFactory default Quartz secara otomatis memanggil setter tersebut ketika pekerjaan dibuat instance-nya, sehingga mencegah kebutuhan untuk secara eksplisit mengeluarkan nilai dari peta dalam metode eksekusi kita.

6. Pemicu

Objek pemicu digunakan untuk memicu eksekusi Pekerjaan .

Saat kami ingin menjadwalkan Pekerjaan , kami perlu membuat contoh pemicu dan menyesuaikan propertinya untuk mengonfigurasi persyaratan penjadwalan kami:

Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("myTrigger", "group1") .startNow() .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(40) .repeatForever()) .build();

A Trigger may also have a JobDataMap associated with it. This is useful for passing parameters to a Job that are specific to the executions of the trigger.

There are different types of triggers for different scheduling needs. Each one has different TriggerKey properties for tracking their identities. However, some other properties are common to all trigger types:

  • The jobKey property indicates the identity of the job that should be executed when the trigger fires.
  • The startTime property indicates when the trigger’s schedule first comes into effect. The value is a java.util.Date object that defines a moment in time for a given calendar date. For some trigger types, the trigger fires at the given start time. For others, it simply marks the time that the schedule should start.
  • The endTime property indicates when the trigger’s schedule should be canceled.

Quartz ships with a handful of different trigger types, but the most commonly used ones are SimpleTrigger and CronTrigger.

6.1. Priority

Sometimes, when we have many triggers, Quartz may not have enough resources to immediately fire all of the jobs are scheduled to fire at the same time. In this case, we may want to control which of our triggers gets available first. This is exactly what the priority property on a trigger is used for.

For example, when ten triggers are set to fire at the same time and merely four worker threads are available, the first four triggers with the highest priority will be executed first. When we do not set a priority on a trigger, it uses a default priority of five. Any integer value is allowed as a priority, positive or negative.

In the example below, we have two triggers with a different priority. If there aren't enough resources to fire all the triggers at the same time, triggerA will be the first one to be fired:

Trigger triggerA = TriggerBuilder.newTrigger() .withIdentity("triggerA", "group1") .startNow() .withPriority(15) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(40) .repeatForever()) .build(); Trigger triggerB = TriggerBuilder.newTrigger() .withIdentity("triggerB", "group1") .startNow() .withPriority(10) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(20) .repeatForever()) .build();

6.2. Misfire Instructions

A misfire occurs if a persistent trigger misses its firing time because of the Scheduler being shut down, or in case there are no available threads in Quartz’s thread pool.

The different trigger types have different misfire instructions available. By default, they use a smart policy instruction. When the scheduler starts, it searches for any persistent triggers that have misfired. After that, it updates each of them based on their individually configured misfire instructions.

Let's take a look at the examples below:

Trigger misFiredTriggerA = TriggerBuilder.newTrigger() .startAt(DateUtils.addSeconds(new Date(), -10)) .build(); Trigger misFiredTriggerB = TriggerBuilder.newTrigger() .startAt(DateUtils.addSeconds(new Date(), -10)) .withSchedule(SimpleScheduleBuilder.simpleSchedule() .withMisfireHandlingInstructionFireNow()) .build();

We have scheduled the trigger to run 10 seconds ago (so it is 10 seconds late by the time it is created) to simulate a misfire, e.g. because the scheduler was down or didn't have a sufficient amount of worker threads available. Of course, in a real-world scenario, we would never schedule triggers like this.

In the first trigger (misFiredTriggerA) no misfire handling instructions are set. Hence a called smart policy is used in that case and is called: withMisfireHandlingInstructionFireNow(). This means that the job is executed immediately after the scheduler discovers the misfire.

The second trigger explicitly defines what kind of behavior we expect when misfiring occurs. In this example, it just happens to be the same smart policy.

6.3. SimpleTrigger

SimpleTrigger is used for scenarios in which we need to execute a job at a specific moment in time. This can either be exactly once or repeatedly at specific intervals.

An example could be to fire a job execution at exactly 12:20:00 AM on January 13, 2018. Similarly, we can start at that time, and then five more times, every ten seconds.

In the code below, the date myStartTime has previously been defined and is used to build a trigger for one particular timestamp:

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startAt(myStartTime) .forJob("job1", "group1") .build();

Next, let's build a trigger for a specific moment in time, then repeating every ten seconds ten times:

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger() .withIdentity("trigger2", "group1") .startAt(myStartTime) .withSchedule(simpleSchedule() .withIntervalInSeconds(10) .withRepeatCount(10)) .forJob("job1") .build();

6.4. CronTrigger

The CronTrigger is used when we need schedules based on calendar-like statements. For example, we can specify firing-schedules such as every Friday at noon or every weekday at 9:30 am.

Cron-Expressions are used to configure instances of CronTrigger. These expressions consist of Strings that are made up of seven sub-expressions. We can read more about Cron-Expressions here.

In the example below, we build a trigger that fires every other minute between 8 am and 5 pm, every day:

CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger3", "group1") .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 8-17 * * ?")) .forJob("myJob", "group1") .build();

7. Conclusion

Pada artikel ini, kami telah menunjukkan cara membuat Penjadwal untuk memicu Pekerjaan . Kami juga melihat beberapa opsi pemicu yang paling umum digunakan: SimpleTrigger dan CronTrigger .

Quartz dapat digunakan untuk membuat jadwal sederhana atau kompleks untuk melaksanakan lusinan, ratusan, atau bahkan lebih banyak pekerjaan. Informasi lebih lanjut tentang kerangka kerja dapat ditemukan di situs web utama.

Kode sumber contoh dapat ditemukan di GitHub.