Java Quartz Scheduler

Chắc hẳn ai trong chúng ta cũng đã từng gặp phải bài toán lập lịch. Ví dụ như đồng bộ dữ liệu khách hàng sau mỗi 5 phút, hoặc chạy các job xuất báo cáo vào 6h chiều ngày thứ 6 hàng tuần, hoặc gửi email cho khách hàng về tỉ giá giao dịch chứng khoán đầu ngày giao dịch v.v... Thư viện Java Quartz giúp bạn dễ dàng xử lý được các bài toán như vậy.

Hôm nay chúng ta sẽ tạo 1 project demo về việc sử dụng thư viện Quartz. Hãy tạo 1 maven project với cấu trúc như sau:

Trong file pom.xml chúng ta sẽ khai báo sử dụng thư viện Quartz như sau:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>vuta.quartz.example</groupId>
	<artifactId>quartz-scheduler-example</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>Quartz Scheduler :: example</name>
	<url>http://maven.apache.org</url>

	<properties>
		<quartz.version>2.2.1</quartz.version>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>${quartz.version}</version>
		</dependency>
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz-jobs</artifactId>
			<version>${quartz.version}</version>
		</dependency>
	</dependencies>
</project>

Quartz có 3 thành phần cơ bản:

  • Task/Job: Đây chính là các tác vụ cần thực thi trong chương trình(chứa code xử lý business logic)
  • Listener: Đây là 1 thành phần của framework, framework sẽ gọi đến thành phần này tạo cho bạn cơ hội chạy code trong một số trường hợp như khi tác vụ bắt đầu, kết thúc hoặc bị từ chối (bị cấm) .
  • Trigger: Tạo ra mối quan hệ giữa 2 thành phần kể trên, và có khả năng thiết lập các khoảng thời gian theo mẫu hình để tác vụ có thể được thực thi(Ví dụ: mỗi 5 phút, 5h sáng hàng ngày, ...)

1. Job task

Job task đại diện cho các tác vụ mà chương trình của bạn phải cần phải xử lý. Ví dụ như tổng hợp tỉ giá giao dịch chứng khoán trong cơ sở dữ liệu và gửi email về số liệu cho khách hàng, xuất báo cáo, ... có thể là bất cứ nghiệp vụ nào khác 😄

Lưu ý: trong khi khai báo Quartz job bạn phải implement org.quartz.Job interface. Trong ví dụ này là in ra Hello world

package vuta.quartz.example;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class HelloJob implements Job {
	
	public void execute(JobExecutionContext context) throws JobExecutionException {
		
		System.out.println("Hello World!");
	}

}

2. Job listener

Lưu ý: trong khi khai báo Quartz listener bạn phải implement org.quartz.JobListener interface, 4 phương thức bên dưới sẽ được override

  • getName: Trả về tên của job listener.
  • jobToBeExecuted: Quartz sẽ gọi phương thức này khi tác vụ chuẩn bị được thực thi.
  • jobExecutionVetoed: Quartz sẽ gọi phương thức này khi việc thực hiện tác vụ bị cấm từ trigger.
  • jobWasExecuted: Quartz sẽ gọi phương thức này khi tác vụ đã được thực thi.
package vuta.quartz.example;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobListener;

public class HelloJobListener implements JobListener {

	public String getName() {
		return "HelloJobListener";
	}

	public void jobToBeExecuted(JobExecutionContext context) {

		final String jobName = context.getJobDetail().getKey().toString();
		System.out.println("jobToBeExecuted: " + jobName + " is starting...");

	}

	public void jobExecutionVetoed(JobExecutionContext context) {
		System.out.println("jobExecutionVetoed");
	}

	public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
		System.out.println("jobWasExecuted");

		final String jobName = context.getJobDetail().getKey().toString();
		System.out.println("Job : " + jobName + " is finished!!");

		if (!jobException.getMessage().equals("")) {
			System.out.println("Exception thrown by: " + jobName + " Exception: " + jobException.getMessage());
		}
	}
}

3. Trigger

Trigger đại diện cho mối quan hệ giữa tác vụ và listener, nó chịu trách nhiệm tạo tác vụ, tạo listener, tạo các sự kiện (dựa trên khoảng thời gian)

package vuta.quartz.example;

import org.quartz.CronScheduleBuilder;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.KeyMatcher;

public class HelloCronTrigger {

	public static void main(String[] args) throws Exception {

		final JobKey jobKey = new JobKey("HelloName", "group1");
		final JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity(jobKey).build();

		final Trigger trigger = TriggerBuilder.newTrigger().withIdentity("HelloTriggerName", "group1")
				.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();

		final Scheduler scheduler = new StdSchedulerFactory().getScheduler();

		// Listener attached to jobKey
		scheduler.getListenerManager().addJobListener(new HelloJobListener(), KeyMatcher.keyEquals(jobKey));

		scheduler.start();
		scheduler.scheduleJob(job, trigger);
	}
}

Sau khi chạy main() ta sẽ thấy kết quả Hello World được in ra sau mỗi 5 giây

jobToBeExecuted: group1.HelloName is starting... Hello World! jobWasExecuted Job : group1.HelloName is finished!! jobToBeExecuted: group1.HelloName is starting... Hello World! jobWasExecuted Job : group1.HelloName is finished!!

Về việc cấu hình các khoảng thời gian thì các bạn có thể xem thêm tại đây.