Spring 3 + Quartz 1.8.6 scheduler example

Updated on 25 July 2012 – Upgrade article to use Spring 3 and Quartz 1.8.6 (it was Spring 2.5.6 and Quartz 1.6)

In this tutorial, we will show you how to integrate Spring with Quartz scheduler framework. Spring comes with many handy classes to support Quartz, and decouple your class to Quartz APIs.

Tools Used :

  1. Spring 3.1.2.RELEASE
  2. Quartz 1.8.6
  3. Eclipse 4.2
  4. Maven 3
Why NOT Quartz 2?
Currently, Spring 3 is still NOT support Quartz 2 APIs, see this SPR-8581 bug report. Will update this article again once bug fixed is released.

1. Project Dependency

You need following dependencies to integrate Spring 3 and Quartz 1.8.6

File : pom.xml

...
<dependencies>
 
	<!-- Spring 3 dependencies -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-core</artifactId>
		<version>3.1.2.RELEASE</version>
	</dependency>
 
	<!-- QuartzJobBean in spring-context-support.jar -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-context-support</artifactId>
		<version>3.1.2.RELEASE</version>
	</dependency>
 
	<!-- Spring + Quartz need transaction -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-tx</artifactId>
		<version>3.1.2.RELEASE</version>
	</dependency>
 
	<!-- Quartz framework -->
	<dependency>
		<groupId>org.quartz-scheduler</groupId>
		<artifactId>quartz</artifactId>
		<version>1.8.6</version>
	</dependency>
 
</dependencies>
...

2. Scheduler Task

Create a normal Java class, this is the class you want to schedule in Quartz.

File : RunMeTask.java

package com.mkyong.common;
 
public class RunMeTask {
	public void printMe() {
		System.out.println("Spring 3 + Quartz 1.8.6 ~");
	}
}

3. Declare Quartz Scheduler Job

With Spring, you can declare Quartz job in two ways :

3.1 MethodInvokingJobDetailFactoryBean
This is the simplest and straightforward method, suitable for simple scheduler.

<bean id="runMeJob" 
 	class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
 
	<property name="targetObject" ref="runMeTask" />
	<property name="targetMethod" value="printMe" />
 
</bean>

3.2 JobDetailBean
The QuartzJobBean is more flexible and suitable for complex scheduler. You need to create a class extends the Spring’s QuartzJobBean, and define the method you want to schedule in executeInternal() method, and pass the scheduler task (RunMeTask) via setter method.

File : RunMeJob.java

package com.mkyong.common;
 
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
 
public class RunMeJob extends QuartzJobBean {
	private RunMeTask runMeTask;
 
	public void setRunMeTask(RunMeTask runMeTask) {
		this.runMeTask = runMeTask;
	}
 
	protected void executeInternal(JobExecutionContext context)
		throws JobExecutionException {
 
		runMeTask.printMe();
 
	}
}

Configure the target class via jobClass and method to run via jobDataAsMap.

<bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean">
 
	<property name="jobClass" value="com.mkyong.common.RunMeJob" />
 
	<property name="jobDataAsMap">
		<map>
			<entry key="runMeTask" value-ref="runMeTask" />
		</map>
	</property>
 
</bean>

4. Trigger

Configure Quartz trigger to define when will run your scheduler job. Two type of triggers are supported :

4.1 SimpleTrigger
It allows to set the start time, end time, repeat interval to run your job.

        <!-- Simple Trigger, run every 5 seconds -->
	<bean id="simpleTrigger" 
                class="org.springframework.scheduling.quartz.SimpleTriggerBean">
 
		<property name="jobDetail" ref="runMeJob" />
		<property name="repeatInterval" value="5000" />
		<property name="startDelay" value="1000" />
 
	</bean>

4.2 CronTrigger
It allows Unix cron expression to specify the dates and times to run your job.

	<!-- Cron Trigger, run every 5 seconds -->
	<bean id="cronTrigger"
		class="org.springframework.scheduling.quartz.CronTriggerBean">
 
		<property name="jobDetail" ref="runMeJob" />
		<property name="cronExpression" value="0/5 * * * * ?" />
 
	</bean>
Note
The Unix cron expression is highly flexible and powerful, read more in following websites :

  1. http://en.wikipedia.org/wiki/CRON_expression
  2. http://www.quartz-scheduler.org/docs/examples/Example3.html

5. Scheduler Factory

Create a Scheduler factory bean to integrate both job detail and trigger together.

   <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
	<property name="jobDetails">
	   <list>
	      <ref bean="runMeJob" />
	   </list>
	</property>
 
	<property name="triggers">
	    <list>
		<ref bean="simpleTrigger" />
	    </list>
	</property>
   </bean>

6. Spring Bean Configuration File

Complete Spring’s bean configuration file.

File : Spring-Quartz.xml

<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">
 
	<bean id="runMeTask" class="com.mkyong.common.RunMeTask" />
 
	<!-- Spring Quartz -->
	<bean name="runMeJob" class="org.springframework.scheduling.quartz.JobDetailBean">
 
		<property name="jobClass" value="com.mkyong.common.RunMeJob" />
 
		<property name="jobDataAsMap">
		  <map>
			<entry key="runMeTask" value-ref="runMeTask" />
		  </map>
		</property>
 
	</bean>
 
	<!-- 
	<bean id="runMeJob" 
            class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> 
		<property name="targetObject" ref="runMeTask" /> 
		<property name="targetMethod" value="printMe" /> 
	</bean> 
	-->
 
	<!-- Simple Trigger, run every 5 seconds -->
	<bean id="simpleTrigger" 
                class="org.springframework.scheduling.quartz.SimpleTriggerBean">
 
		<property name="jobDetail" ref="runMeJob" />
		<property name="repeatInterval" value="5000" />
		<property name="startDelay" value="1000" />
 
	</bean>
 
	<!-- Cron Trigger, run every 5 seconds -->
	<bean id="cronTrigger" 
                class="org.springframework.scheduling.quartz.CronTriggerBean">
 
		<property name="jobDetail" ref="runMeJob" />
		<property name="cronExpression" value="0/5 * * * * ?" />
 
	</bean>
 
	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
			<list>
				<ref bean="runMeJob" />
			</list>
		</property>
 
		<property name="triggers">
			<list>
				<ref bean="simpleTrigger" />
			</list>
		</property>
	</bean>
 
</beans>

7. Demo

Run it ~

package com.mkyong.common;
 
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class App 
{
    public static void main( String[] args ) throws Exception
    {
    	new ClassPathXmlApplicationContext("Spring-Quartz.xml");
    }
}

Output to console.

Jul 25, 2012 3:23:09 PM org.springframework.scheduling.quartz.SchedulerFactoryBean startScheduler
INFO: Starting Quartz Scheduler now
Spring 3 + Quartz 1.8.6 ~ //run every 5 seconds
Spring 3 + Quartz 1.8.6 ~

Download Source Code

Download it – Spring3-Quartz-Example.zip (25 KB)

References

  1. Using Quartz Scheduler with Spring
  2. Quartz Official Website
  3. Struts 2 + Spring 3 + Quartz 1.8 example
Tags :

About the Author

mkyong
Founder of Mkyong.com and HostingCompass.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

  • Pingback: URL()

  • raju

    Hi mkyong,

    I used Quartz scheduler in my Spring-Hibernate App based on You Nice Explanation.It is working fine,But The Threads Started for Quartz Scheduler are not destroying…and my server gives Errors(Memory Leaks) like….

    org.apache.catalina.loader.WebappClassLoader clearReferencesThreads
    SEVERE: The web application [/app] appears to have started a thread named [schedularbeanfactoryobj_Worker-1] but has failed to stop it. This is very likely to create a memory leak.
    ….
    ….

    I have Tried With Many solutions to shutdown those threads but could not fixed.Can anybody Help To fix this.(i am using spring3.2.2 and quartz1.8.6)and also tried with quartz2.2.

    Thanks
    raju.

  • Diana

    Hi, is it possible to make spring not to trigger the cronjob is the previous trigged job is still running?

    • Humberto Souza

      Hi Diana,

      The jobs are synchonous by default. So, even if you trigger the task that is already executing, it will not fire the second.
      If you want fire the same task at same time, should use assync methods.

    • raju

      Hi,

      From Spring Doc…

      “By default, Quartz Jobs are stateless, resulting in the possibility of jobs interfering with each other. If
      you specify two triggers for the same JobDetail, it might be possible that before the first job has
      finished, the second one will start. If JobDetail classes implement the Stateful interface, this won’t
      happen. The second job will not start before the first one has finished. To make jobs resulting from the
      MethodInvokingJobDetailFactoryBean non-concurrent, set the concurrent flag to false.

    • Diana

      I finally created a class to be a singleton. It’s an static property of the task (not the job), with an internal flag (private Boolean running = false;) with a method to change status (public void changeStatus() {running = !running;}), and a method to know its value (isRunning()).
      So when the task is running, it checks if there is another thread running:

      if (!mySingleton.isRunning()) {
      mySingleton.changeStatus();
      //whatever the task has to do here
      mySingleton.changeStatus();
      } else {
      logger.warn(“Task won’t be executed, there is another instance of this job running.”);
      }

      Something like that, I don’t have my code here. But from everything I tried, it was the only thing that actually avoid running the same task twice at the same time. (Of course, I haven’t tried all the possibilities, but that solution worked for me).

  • Prasad

    Sir ,
    I am using Spring 3.1.1 and quartz 1.8.5 like above example .but i am getting exception like below .anyone help me !

    Exception in thread “main” org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘job’ defined in class path resource [META-INF/applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property ‘jobclass’ of bean class [org.springframework.scheduling.quartz.JobDetailBean]: Bean property ‘jobclass’ is not writable or has an invalid setter method. Did you mean ‘jobClass’?
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1396)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1118)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139)
    at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
    at com.rcent.samples.SchedulerApp.main(SchedulerApp.java:11)
    Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property ‘jobclass’ of bean class [org.springframework.scheduling.quartz.JobDetailBean]: Bean property ‘jobclass’ is not writable or has an invalid setter method. Did you mean ‘jobClass’?
    at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1064)
    at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:924)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:76)
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:58)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1393)
    … 13 more

  • Nish

    Hi..

    Thanks..it works gud but i have spring application, I am importing the quarts-job.xml in application-servlet.xml. There are no error’s and during the server startup it shows” Starting Quartz Scheduler now” but the task is not fired Any idea what might be the issue.

    Thanks,
    Nishith

    • raju

      can you post your Quartz Configurations..

  • Marcelo Lior

    Great contribution! Straight to the point. Thanks a lot

  • Suraj

    When I execute the App.java, I am not able to see any output on the console.

    The Eclipse console only shows:
    Sep 18, 2013 12:53:32 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
    INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@1113708: startup date [Wed Sep 18 12:53:32 IST 2013]; root of context hierarchy
    Sep 18, 2013 12:53:32 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
    INFO: Loading XML bean definitions from class path resource [spring-quartz.xml]
    Sep 18, 2013 12:53:32 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
    INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1a33d48: defining beans [runMeTask,runMeJob,simpleTrigger]; root of factory hierarchy

    Can someone help me to get this resolved?
    I am using spring 3.1.2 and quartz 1.8.6

    Thanking in advance!!

  • Diana

    Thank you very much, these is better than what I used to schedule a job. In fact, it solved me a problem. Thank you very much!

    • mkyong

      Its ok

  • Catalin

    How can i do a Unit test for this scheduler to see if it print the message in the write time interval?

  • Suman

    Very good article. its easy to understand

  • Bilal

    It is very simple and concise article to understand the basic concepts. Thanks

  • Darshan

    Could not autowire field: org.processor.repository.NotificationRepository org.processor.services.ProcessorService.notificationRepository; nested exception is org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.JobDetailBean] for bean with name ‘runMeJob’ defined in ServletContext resource [/WEB-INF/quartz-job.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.JobDetailBean has interface org.quartz.JobDetail as super class

    when i try to integrate this project in my maven project i am recieving above error?
    please help

  • Alimotte

    Hi,
    In my application youre tutorial give me this error:

    java.lang.NoClassDefFoundError: org/w3c/dom/ElementTraversal

    The solution to resolve it was:

    xml-apis
    xml-apis
    1.4.01

    Thank’s for all your help! Everyday when I have a problem, you have the solution! ;)

    • Alimotte

      It’s a fail, sorry! :D
      Add in pom.xml:

      xml-apis
      xml-apis
      1.4.01

      • Alimotte

        Ok balise is escaped…
        so:
        dependency
        groupId org.quartz-scheduler /groupId
        artifactId quartz /artifactId
        version 1.8.6 /version
        /dependency

        Sorry for spam :)

  • Dmitry

    Your example works only if you use

    If you like to work this application with JobDetailsBean you should fixed it:

    public class RunMeJob extends JobDetailBean { // it is empty.
    }
    and RunMeTask must implement Job interface
    public class RunMeTask implements Job {
    public void execute(JobExecutionContext jec) throws JobExecutionException {
    System.out.println(“Quartz test job executed.”);
    }
    }

  • Swetha

    Thanks Mkyong, you always explain the concepts simple and easy so that novice person also can understand. your articles are very helpful to me. Thank you so much.

  • name

    It seems that issue of https://jira.springsource.org/browse/SPR-8581 has labeled as won’t fix so you can update your article.

  • http://www.babaniyi.ws Ayodeji Babaniyi

    There is a small addition needed for the downloaded version to fully build and work out of the box: Simply add this dependency to the pom.xml

    org.junit
    com.springsource.junit
    3.8.2
    test
    jar

    That way it would compile and run out of the box.

  • http://findeclinic.com Findeclinic

    The bug SPR-8581, looks resolved. Could you try updating? I failed :(

  • Guillermo

    Simple, well explained and functional. I have lost the count of the times I ended up in your blog looking for answers.

    Thanks!

    • rybek

      I fully agree with Gullermo.

      Thanks! and keep the posts comming ;)

      • Hector

        A Co-worker and I just said “We always land on this dude’s blog!” Thank you Mkyong

  • James

    Nice example. Helped a lot. Thanks.

  • siva

    Excellent post, thanks!!!!!

  • ilia

    Thank you !!!

  • Catherine

    Hi mkyong,
    Your articles have always been a great help for me.
    Thank you so much!

  • Satya

    Hi mkyong,

    I’m always follows your articles, it’s awesome to learn new things. i have one problem and I’m using spring with Quartz and every
    thing working fine but some previous cofigured
    triggers also got executed because they are stored
    in Quartz tables. Manually we can delete all
    un configured triggers and execute the application
    but that is not a good practice, right? so i want to
    remove all the triggers through any spring+quartz property
    or some other solution , i think there is spring+quartz
    property for this problem.but If any property is available
    to handle this problem and if you know plz forward me your
    valuable solution .
    Actually the scenario is ,
    suppose when i have configured 3 triggers in spring configuration file like

    when server started all the triggers stored in Quartz tables with
    corresponding cron triggers and job details. But if i
    remove any of the trigger in my configuration like in above for example i removed second Trigger , one thing i removed that trigger from coniguration file only but not
    from Quartz tables. at that time DBtrigger (removed trigger)
    also executed. How to avoid that problem. can anyone help to me.
    it’s very useful to me. i googled lot of sites but i didn’t
    get a solution. In spring + Quartz integration , is there
    any property is there to handle this problem or we need to
    do some thing for this problem.

    Please tell me if you know the solution.

    Thanks in advance.

    • sri

      Hi ,

      I am also looking for same thing. Quartz property to delete jobdetails from quartz table. please send if there is any property .

      Thank you

  • KB

    Hi mkyong,

    I am facing a problem with Quartz+Spring implementation in my project. My production environment is clustered i.e two jboss instances. Therefore the time at which the job is scheduled say at 5PM, the same from each server instance gets triggered, therefore causing duplicate runs of the same job. How do I ensure that only one job instance runs in a clustered environment?

    Thanks and regards,
    KB.

    • Humberto R. Souza

      Hi KB,

      The simplest way:
      You may use a flag in your database to indicate if a proccess has begun or not.

      Other ways:
      Use serializable objects, if possible, and try avoid static variables;
      Multithread may be controlled by the package java.util.concurrent, but depends on your scenario and JDK version.

  • Pingback: Quartz one time job on application startup | Code and Programming()