Categories: spring

Spring 4 + Quartz Scheduler Integration Example

In this post we will see how to schedule Jobs using Quartz Scheduler with Spring. Spring provides couple of classes that simplify the usage of Quartz within Spring-based applications. Let’s get going.


Following technologies being used:

  • Spring 4.0.6.RELEASE
  • Quartz 2.2.1
  • Maven 3
  • JDK 1.6
  • Eclipse JUNO Service Release 2

Project directory structure:

Following will be the final project directory structure for this example:

Let’s now add the content mentioned in above structure explaining each in detail.

Step 1: Provide Dependencies in Maven pom.xml

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.websystique.spring</groupId>
  <artifactId>SpringQuartzIntegrationExample</artifactId>
  <version>1.0.0</version>
  <packaging>jar</packaging>
  <name>SpringQuartzIntegrationExample</name>

 <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>
  <!-- Transaction dependency is required with Quartz integration -->
  <dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-tx</artifactId>
   <version>${springframework.version}</version>
  </dependency>
  
  <!-- Quartz framework -->
  <dependency>
   <groupId>org.quartz-scheduler</groupId>
   <artifactId>quartz</artifactId>
   <version>${quartz.version}</version>
  </dependency>
 </dependencies>
 <build>
  <pluginManagement>
   <plugins>
    <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-compiler-plugin</artifactId>
     <version>3.2</version>
     <configuration>
      <source>1.6</source>
      <target>1.6</target>
     </configuration>
    </plugin>
   </plugins>
  </pluginManagement>
 </build>

</project>

Step 2: Configure Jobs in Quartz Scheduler

There are 2 ways to configure a Job in Spring using Quartz

A : Using MethodInvokingJobDetailFactoryBean

Really handy when you just need to invoke a method on a specific bean. This is the simplest among two.

 <!-- For times when you just need to invoke a method on a specific object -->
 <bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  <property name="targetObject" ref="myBean" />
  <property name="targetMethod" value="printMessage" />
 </bean>

Above job configuration simply invokes printMessage method of bean myJobBean which is simple POJO

B : Using JobDetailFactoryBean

When you need more advanced setup, need to pass data to job, being more flexible.

 <!-- For times when you need more complex processing, passing data to the scheduled job -->
 <bean name="complexJobDetail"  class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
  <property name="jobClass" value="com.websystique.spring.quartz.ScheduledJob" />
  <property name="jobDataMap">
   <map>
    <entry key="anotherBean" value-ref="anotherBean" />
   </map>
  </property>
  <property name="durability" value="true" />
 </bean>

jobClass refers to a class which extends QuartzJobBean, an implementation of Quartz job interface. On invocation of this job, it’s executeInternal method gets called.
jobDataMap provides opportunity to pass some data to underlying job bean. In this case, we are passing a bean ‘anotherBean’ which will be used by ScheduledJob.

Below is the referred jobclass (ScheduledJob) implementation.

com.websystique.spring.quartz.ScheduledJob

package com.websystique.spring.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.websystique.spring.scheduling.AnotherBean;

public class ScheduledJob extends QuartzJobBean{

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

 public void setAnotherBean(AnotherBean anotherBean) {
  this.anotherBean = anotherBean;
 }
}

Step 3: Configure Triggers to be used in Quartz Scheduler

Trigger defines the time when scheduler will run your scheduled job. There are two possible trigger type:

A: Simple Trigger , using SimpleTriggerFactoryBean
You can specify start time, delay between triggers and repeatInterval(frequency) to run the job.

 <!-- Run the job every 2 seconds with initial delay of 1 second -->
 <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>

B: Cron Trigger , using CronTriggerFactoryBean

It’s more flexible and allows you to choose scheduled job at specific instance (time, day, date,..) and frequency in future.

 <!-- Run the job every 5 seconds only on Weekends -->
 <bean id="cronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  <property name="jobDetail" ref="complexJobDetail" />
  <property name="cronExpression" value="0/5 * * ? * SAT-SUN" />
 </bean>

Step 4: Configure SchedulerFactoryBean that creates and configures Quartz Scheduler

SchedulerFactoryBean glues together jobDetails and triggers to Configure Quartz Scheduler

 <!-- Scheduler factory bean to glue together jobDetails and triggers to 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>

Below shown is complete context file for our example

src/main/resources/quartz-context.xml

<?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="com.websystique.spring" />


 <!-- For times when you just need to invoke a method on a specific object -->
 <bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  <property name="targetObject" ref="myBean" />
  <property name="targetMethod" value="printMessage" />
 </bean>


 <!-- For times when you need more complex processing, passing data to the scheduled job -->
 <bean name="complexJobDetail"  class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
  <property name="jobClass" value="com.websystique.spring.quartz.ScheduledJob" />
  <property name="jobDataMap">
   <map>
    <entry key="anotherBean" value-ref="anotherBean" />
   </map>
  </property>
  <property name="durability" value="true" />
 </bean>


 <!-- Run the job every 2 seconds with initial delay of 1 second -->
 <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>


 <!-- Run the job every 5 seconds only on Weekends -->
 <bean id="cronTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  <property name="jobDetail" ref="complexJobDetail" />
  <property name="cronExpression" value="0/5 * * ? * SAT-SUN" />
 </bean>


 <!-- Scheduler factory bean to glue together jobDetails and triggers to 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>

</beans>

Step 5: Create simple POJO’s Task Beans used in this example

com.websystique.spring.scheduling.MyBean

package com.websystique.spring.scheduling;

import org.springframework.stereotype.Component;

@Component("myBean")
public class MyBean {

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

com.websystique.spring.scheduling.AnotherBean


package com.websystique.spring.scheduling;

import org.springframework.stereotype.Component;

@Component("anotherBean")
public class AnotherBean {
 
 public void printAnotherMessage(){
  System.out.println("I am called by Quartz jobBean using CronTriggerFactoryBean");
 }
 
}

Step 6: Create Main, and Run the application

package com.websystique.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 it as Java application, you will see following output.

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

You can see that SimpleTrigger invoked job is called every two seconds while the one from CronTrigger is called every five seconds.

That’s it.

Download Source Code


References

View Comments

  • For the SchedulerFactoryBean config, why are you including the "jobDetails" along with the "triggers" elements? Seems that the "triggers" elements are enough since those configs reference the jobs. Thanks!

    • Hi Baker, i see what you mean, agree that it should work even without jobDetails. Good remark, thanks.

      • Sounds like having both does not cause an issue for you, though. We're trying to debug an issue where the job runs continuously and not according the the schedule/trigger. Our configuration (that I've inherited) also includes both "jobDetails" and "triggers" sections, which appears to be the norm for some implementations even though the documentation on the Spring website only includes "triggers". Wasn't sure if you had experience such that both were necessary. Thanks again ...

  • I encountered a weird issue. My QuartzJobBean implementation class cannot get [anotherBean] auto injected with the data configured in jobDataMap. It's always throw a NullPointerException when invoking method in [anotherBean]. So I use JobExecutionContext parameter passed into executeInternal method to get JobDetail, then get [anotherBean] from the jobDataMap.
    protected void executeInternal(JobExecutionContext paramJobExecutionContext) throws JobExecutionException {
    JobDataMap jobDataMap = paramJobExecutionContext.getJobDetail().getJobDataMap();
    anotherBean = (OrderAssignmentJobDataBean) jobDataMap.get("anotherBean");
    ...
    }
    I've already tried @Component annotation for AnotherBean class and xml based configure for beanBean injection. I ma using spring 4.2.5, quartz 2.2.1.

  • Could you please developed a Spring MVC code which will query to database in every 5 mins and fetches a records ??

    • Hi Prateek,
      Even if it can be done, this kind of [non-interactive] functionality is better suited for spring batch. Have a look at this post.

  • I tried to run this code, but the cron scheduler print statement is never being displayed to me somehow. i checked everything seems correct not sure whats going wrong.

  • Thank you very much for wonderful tutorial. Can you please provide a post using only annotations so that we can get rid of clumsy xml code.

  • Hello,
    Thanks for sharing.
    A little point : You use the same name
    for "AnotherBean" class name, component name, map key and entry, and
    object name in the ScheduleJob class. A bit confusing... and this
    practise hides the role of each definition in the whole configuration.
    grx_jn

Share
Published by

Recent Posts

Spring Boot + AngularJS + Spring Data + JPA CRUD App Example

In this post we will be developing a full-blown CRUD application using Spring Boot, AngularJS, Spring Data, JPA/Hibernate and MySQL,…

8 years ago

Spring Boot Rest API Example

Spring Boot complements Spring REST support by providing default dependencies/converters out of the box. Writing RESTful services in Spring Boot…

8 years ago

Spring Boot WAR deployment example

Being able to start the application as standalone jar is great, but sometimes it might not be possible to run…

8 years ago

Spring Boot Introduction + hello world example

Spring framework has taken the software development industry by storm. Dependency Injection, rock solid MVC framework, Transaction management, messaging support,…

8 years ago

Secure Spring REST API using OAuth2

Let's secure our Spring REST API using OAuth2 this time, a simple guide showing what is required to secure a…

8 years ago

AngularJS+Spring Security using Basic Authentication

This post shows how an AngularJS application can consume a REST API which is secured with Basic authentication using Spring…

8 years ago