12/08/2018, 14:09

Tạo scheduler Jobs trong Spring sử dụng Quartz Scheduler

Trong bài này tôi sẽ giới thiệu cách tạo scheduler Jobs trong Spring sử dụng Quartz Scheduler. Công cụ và môi trường phát triển: Spring 4.0.6.RELEASE Quartz 2.2.1 Maven 3 JDK 1.8 Eclipse Neon Release (4.6.0) Cấu trúc project: 1. Thư viện sử dụng trong project ...

Trong bài này tôi sẽ giới thiệu cách tạo scheduler Jobs trong Spring sử dụng Quartz Scheduler.

Quartz_Logo_large.jpg

Công cụ và môi trường phát triển:

  • Spring 4.0.6.RELEASE
  • Quartz 2.2.1
  • Maven 3
  • JDK 1.8
  • Eclipse Neon Release (4.6.0)

Cấu trúc project:

Screenshot from 2016-10-31 01:27:41.png

1. Thư viện sử dụng trong project

    <properties>
		<springframework.version>4.0.6.RELEASE</springframework.version>
		<quartz.version>2.2.1</quartz.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${springframework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context-support</artifactId>
			<version>${springframework.version}</version>
		</dependency>
		 
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${springframework.version}</version>
		</dependency>

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

2. Configure Jobs trong Quartz Scheduler

Có 2 cách để configure job trong Spring Quartz

  • Sử dụng MethodInvokingJobDetailFactoryBean

Đây là cách đơn giản nhất trong 2 cách để gọi 1 method đối với 1 bean cụ thể

  
	<bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="firstBean" />
		<property name="targetMethod" value="printMessage" />
	</bean>

Trong job configuration trên ta đơn giản chỉ gọi printMessage method trong firstBean.

  • Sử dụng JobDetailFactoryBean

Đây là cách làm khi ta cần thiết lập nâng cao cho việc setting job, pass data một cách flexible cho job.

 
	<bean name="complexJobDetail" 	class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
		<property name="jobClass" value="demo.spring.quartz.ScheduledJob" />
		<property name="jobDataMap">
			<map>
				<entry key="secondBean" value-ref="secondBean" />
			</map>
		</property>
		<property name="durability" value="true" />
	</bean>

Trong configuration trên ta đã configure jobClass refer tới cách extends QuartzJobBean, implement Quartz job interface. Trong cách gọi job này, method executeInternal đã được gọi. jobDataMap cho phép ta truyền data cho bean job. Trong trường hợp này, ta đã truyền secondBean sễ sử dụng bởi ScheduledJob.

Dưới đây là referred jobclass cài đặt ScheduledJob

package demo.spring.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import demo.spring.scheduling.SecondBean;

public class ScheduledJob extends QuartzJobBean {

	private SecondBean secondBean;

	@Override
	protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException {
		secondBean.printAnotherMessage();
	}

	public void setAnotherBean(SecondBean secondBean) {
		this.secondBean = secondBean;
	}
}

3. Configure Triggers cho việc sử dụng Quartz Scheduler

Trigger xác dịnh khoảng thời gian cho 1 scheduler job. Ta có 2 cách để kích hoạt trigger:

  • Simple Trigger : Các đơn giản nhất là sử dụng SimpleTriggerFactoryBean

Chúng ta có thể chỉ cụ thể về thời gian bắt đầu, khoảng thời gian delay giữa các triggers và khoảng thời gian lập lại 1 job.

	 
	<bean id="simpleTrigger"  class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
		<property name="jobDetail" ref="simpleJobDetail" />
		<property name="startDelay" value="1000" />
		<property name="repeatInterval" value="2000" />
	</bean>
  • Cron Trigger : sử dụng CronTriggerFactoryBean

Cách này flexible hơn cách 1. Nó cho phép ta chọn 1 intance job cụ thể (time, day, date...) và tần suất trong tương lai.

 
	<bean id="cronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<property name="jobDetail" ref="complexJobDetail" />
		<property name="cronExpression" value="0/5 * * ? * SAT-SUN" />
	</bean>

4. Configure SchedulerFactoryBean để tạo và configure Quartz Scheduler

SchedulerFactoryBean kết gắn giữa 2 thành phần jobDetails và triggers để configure Quartz Scheduler

 
	<bean  class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
			<list>
				<ref bean="simpleJobDetail" />
				<ref bean="complexJobDetail" />
			</list>
		</property>

		<property name="triggers">
			<list>
				<ref bean="simpleTrigger" />
				<ref bean="cronTrigger" />
			</list>
		</property>
	</bean>

Dưới đây là file tổng hợp configure quartz demo

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
        					http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<context:component-scan base-package="demo.spring" />

	 
	<bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="firstBean" />
		<property name="targetMethod" value="printMessage" />
	</bean>

	 
	<bean name="complexJobDetail" 	class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
		<property name="jobClass" value="demo.spring.quartz.ScheduledJob" />
		<property name="jobDataMap">
			<map>
				<entry key="secondBean" value-ref="secondBean" />
			</map>
		</property>
		<property name="durability" value="true" />
	</bean>

	 
	<bean id="simpleTrigger"  class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
		<property name="jobDetail" ref="simpleJobDetail" />
		<property name="startDelay" value="1000" />
		<property name="repeatInterval" value="2000" />
	</bean>

	 
	<bean id="cronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
		<property name="jobDetail" ref="complexJobDetail" />
		<property name="cronExpression" value="0/5 * * ? * SAT-SUN" />
	</bean>

	 
	<bean  class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
			<list>
				<ref bean="simpleJobDetail" />
				<ref bean="complexJobDetail" />
			</list>
		</property>

		<property name="triggers">
			<list>
				<ref bean="simpleTrigger" />
				<ref bean="cronTrigger" />
			</list>
		</property>
	</bean>

</beans>

5. Tạo các POJO đơn giản cho Task Bean

 package demo.spring.scheduling;

import org.springframework.stereotype.Component;

@Component("firstBean")
public class FirstBean {

	public void printMessage() {
		System.out.println("FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean");
	}

}
package demo.spring.scheduling;

import org.springframework.stereotype.Component;

@Component("secondBean")
public class SecondBean {

	public void printAnotherMessage(){
		System.out.println("secondBean: I am called by Quartz jobBean using CronTriggerFactoryBean");
	}

}

6. Tạo Main và Run application

 package demo.spring;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AppMain {
	public static void main(String args[]){
		AbstractApplicationContext context = new ClassPathXmlApplicationContext("quartz-context.xml");
	}

}

Run application, output:

INFO: Starting Quartz Scheduler now
FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean
secondBean: I am called by Quartz jobBean using CronTriggerFactoryBean
FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean
FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean
secondBean: I am called by Quartz jobBean using CronTriggerFactoryBean
FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean
FirstBean: I am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean
0