Multi-Job Scheduling Service by using Spring and Quartz

Job Scheduling is so important requirement for the applications. Especially in large-scale projects, working with a lot of jobs can be serious problem. Spring and Quartz have brought significant benefits for the solution of this problem. This article shows how to schedule multi jobs easily by using Spring and Quartz.

Used Technologies :

JDK 1.6.0_21
Spring 3.1.1
Quartz 1.8.5
Maven 3.0.2

STEP 1 : CREATE MAVEN PROJECT

A maven project is created as below. (It can be created by using Maven or IDE Plug-in).

STEP 2 : LIBRARIES

Spring dependencies are added to Maven’ s pom.xml.

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

Quartz dependency is added to pom.xml.

        <dependency>
	    <groupId>org.quartz-scheduler</groupId>
	    <artifactId>quartz</artifactId>
	    <version>1.8.5</version>
	</dependency>

STEP 3 : CREATE TASK CLASSES

A FirstTask Class is created.


package com.otv.task;

import org.apache.log4j.Logger;

/**
 * First Task
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class FirstTask {

	private static Logger log = Logger.getLogger(FirstTask.class);

	/**
	 * Execute this task
	 *
	 */
	public void execute() {
		log.debug("FirstTask runs successfully...");
	}
}

A SecondTask Class is created.


package com.otv.task;

import org.apache.log4j.Logger;

/**
 * Second Task
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class SecondTask {

	private static Logger log = Logger.getLogger(SecondTask.class);

	/**
	 * Execute this task
	 *
	 */
	public void execute() {
		log.debug("SecondTask runs successfully...");
	}
}

STEP 4 : CREATE ISchedulerService INTERFACE

ISchedulerService Interface is created.


package com.otv.service;

/**
 * Scheduler Service Interface
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public interface ISchedulerService {

	/**
	 * Execute First Task
	 *
	 * @param
	 * @throws
	 * @return
	 */
	public void executeFirstTask();

	/**
	 * Execute Second Task
	 *
	 * @param
	 * @throws
	 * @return
	 */
	public void executeSecondTask();
}

STEP 5 : CREATE SchedulerService CLASS

SchedulerService Class is created by implementing ISchedulerService Interface. This service schedules tasks.


package com.otv.service;

import com.otv.task.FirstTask;
import com.otv.task.SecondTask;

/**
 * Scheduler Service Implementation
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class SchedulerService implements ISchedulerService {

	private FirstTask  firstTask;
	private SecondTask secondTask;

	/**
	 * Execute First Task
	 *
	 */
	public void executeFirstTask() {
		getFirstTask().execute();
	}

	/**
	 * Execute Second Task
	 *
	 */
	public void executeSecondTask() {
		getSecondTask().execute();
	}

	/**
	 * Get First Task
	 *
	 * @return FirstTask
	 */
	public FirstTask getFirstTask() {
		return firstTask;
	}

	/**
	 * Set First Task
	 *
	 * @param  firstTask First Task
	 */
	public void setFirstTask(FirstTask firstTask) {
		this.firstTask = firstTask;
	}

	/**
	 * Get Second Task
	 *
	 * @return SecondTask
	 */
	public SecondTask getSecondTask() {
		return secondTask;
	}

	/**
	 * Set Second Task
	 *
	 * @param  secondTask Second Task
	 */
	public void setSecondTask(SecondTask secondTask) {
		this.secondTask = secondTask;
	}
}

STEP 6 : CREATE Application CLASS

Application Class is created. This class runs the application.


package com.otv.starter;

import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Application Starter Class
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class Application {

	/**
	 * Main method of the Application
	 *
	 */
	public static void main(String[] args) {
		new ClassPathXmlApplicationContext("applicationContext.xml");
	}
}

STEP 7 : DEFINE Job Detail CONFIGURATIONS
Job Details can be defined via two ways in Spring. By using MethodInvokingJobDetailFactoryBean or by extending QuartzJobBean. In this example, MethodInvokingJobDetailFactoryBean method has been used.

Usage of MethodInvokingJobDetailFactoryBean
targetObject and targetMethod properties are given to MethodInvokingJobDetailFactoryBean.

	<!-- Job Details-->
	<bean id="FirstTaskJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="SchedulerService" />
		<property name="targetMethod" value="executeFirstTask" />
	</bean>

	<bean id="SecondTaskJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="SchedulerService" />
		<property name="targetMethod" value="executeSecondTask" />
	</bean>

Usage of QuartzJobBean
If JobExecutionContext is required, a new class extending QuartzJobBean should be created as below. For example : when a job is unscheduled and deleted, this step should be used instead of the first(MethodInvokingJobDetailFactoryBean):


package com.otv.job;

import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.otv.service.ISchedulerService;

/**
 * First Job Detail Class
 *
 * @author  onlinetechvision.com
 * @since   24 Feb 2012
 * @version 1.0.0
 *
 */
public class FirstJobDetail extends QuartzJobBean {

	private static Logger logger = Logger.getLogger(FirstJobDetail.class);
	private ISchedulerService schedulerService;
	private JobExecutionContext jobExecutionContext;

	@Override
	protected void executeInternal(JobExecutionContext jobExecContext) throws JobExecutionException {
		//JobExecutionContext is being set...
		setJobExecutionContext(jobExecContext);

		//First Task is being executing...
		getSchedulerService().getFirstTask().execute();
	}

	public ISchedulerService getSchedulerService() {
		return schedulerService;
	}

	public void setSchedulerService(ISchedulerService schedulerService) {
		this.schedulerService = schedulerService;
	}

	public JobExecutionContext getJobExecutionContext() {
		return jobExecutionContext;
	}

	public void setJobExecutionContext(JobExecutionContext jobExecutionContext) {
		this.jobExecutionContext = jobExecutionContext;
	}
}

Job Detail Configuration should be as below :

	<!-- Job Detail-->
	<bean name="FirstJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
 		<property name="jobClass" value="com.otv.job.FirstJobDetail"/>
 		<property name="group" value="JobGroup"/>
 		<property name="jobDataAsMap">
			<map>
				<entry key="schedulerService" value-ref="SchedulerService" />
			</map>
		</property>
	</bean>

STEP 8 : DEFINE Trigger CONFIGURATIONS
Triggers can also be defined via two ways in Spring. By defining SimpleTriggerBean or CronTriggerBean . When SimpleTriggerBean is used, jobDetail, repeatInterval and startDelay properties are defined. When CronTriggerBean is used, jobDetail and cronExpression properties are defined. In this example, repeat interval of first task has been set 5 secs and repeat interval of second task has been set 12 secs .

	<!-- Simple Trigger -->
	<bean id="FirstSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
		<property name="jobDetail" ref="FirstTaskJobDetail" />
		<property name="repeatInterval" value="5000" />
		<property name="startDelay" value="1000" />
	</bean>

	<!-- <bean id="SecondSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
			<property name="jobDetail" ref="SecondTaskJobDetail" />
			<property name="repeatInterval" value="12000" />
			<property name="startDelay" value="1000" />
		</bean> -->	

	<!-- Cron Trigger -->
	<bean id="SecondSimpleTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
 		<property name="jobDetail" ref="SecondTaskJobDetail" />
		<property name="cronExpression" value="0/12 * * * * ?" />
	</bean>

STEP 9 : DEFINE SchedulerFactoryBean CONFIGURATION
Finally, Job Details and Triggers are configured by creating SchedulerFactoryBean.


	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
		   <list>
		      <ref bean="FirstTaskJobDetail" />
		      <ref bean="SecondTaskJobDetail" />
		   </list>
		</property>
		<property name="triggers">
		   <list>
			  <ref bean="FirstSimpleTrigger" />
			  <ref bean="SecondSimpleTrigger" />
		   </list>
		</property>
	</bean>

STEP 10 : CREATE applicationContext.xml
All applicationContext.xml content is shown as below.


<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

	<!-- Beans Declaration -->
	<bean id="FirstTask" class="com.otv.task.FirstTask"></bean>
	<bean id="SecondTask" class="com.otv.task.SecondTask"></bean>

	<bean id="SchedulerService" class="com.otv.service.SchedulerService">
		<property name="firstTask" ref="FirstTask" />
		<property name="secondTask" ref="SecondTask" />
	</bean>

	<!-- Job Details-->
	<bean id="FirstTaskJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="SchedulerService" />
		<property name="targetMethod" value="executeFirstTask" />
	</bean>

	<bean id="SecondTaskJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
		<property name="targetObject" ref="SchedulerService" />
		<property name="targetMethod" value="executeSecondTask" />
	</bean>

	<!-- Simple Trigger -->
	<bean id="FirstSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
		<property name="jobDetail" ref="FirstTaskJobDetail" />
		<property name="repeatInterval" value="5000" />
		<property name="startDelay" value="1000" />
	</bean>
<!--
	<bean id="SecondSimpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
		<property name="jobDetail" ref="SecondTaskJobDetail" />
		<property name="repeatInterval" value="12000" />
		<property name="startDelay" value="1000" />
	</bean>
-->
	<!-- Cron Trigger -->
	<bean id="SecondSimpleTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
 		<property name="jobDetail" ref="SecondTaskJobDetail" />
		<property name="cronExpression" value="0/12 * * * * ?" />
	</bean>

	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
		   <list>
		      <ref bean="FirstTaskJobDetail" />
		      <ref bean="SecondTaskJobDetail" />
		   </list>
		</property>
		<property name="triggers">
		   <list>
			  <ref bean="FirstSimpleTrigger" />
			  <ref bean="SecondSimpleTrigger" />
		   </list>
		</property>
	</bean>

</beans>

STEP 11 : RUN PROJECT

After Application Class is started, below output logs will be shown :


25.02.2012 00:17:18 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:23 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:24 DEBUG (SecondTask.java:22) - SecondTask runs successfully...
25.02.2012 00:17:28 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:33 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:36 DEBUG (SecondTask.java:22) - SecondTask runs successfully...
25.02.2012 00:17:38 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:43 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:48 DEBUG (SecondTask.java:22) - SecondTask runs successfully...
25.02.2012 00:17:48 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:53 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:17:58 DEBUG (FirstTask.java:23) - FirstTask runs successfully...
25.02.2012 00:18:00 DEBUG (SecondTask.java:22) - SecondTask runs successfully...

STEP 12 : DOWNLOAD

OTV_SpringQuartz_MultiJobScheduling

  • Facebook
  • Twitter
  • Reddit
  • LinkedIn
  • DZone
  • Add to favorites
  • Email
  • RSS
  • Delicious
  • Live