Sunday, January 2, 2011

Spring 3 - Quartz Scheduling

In this tutorial we will explore Spring 3's task scheduling support using the Quartz Scheduler. Spring also provides scheduling support using annotations (see Spring 3 - Task Scheduling via Annotations: @Scheduled, @Async), and via XML configuration (see Spring 3 - Task Scheduling via "scheduled-tasks" Element). We will build our application on top of a simple Spring MVC 3 application. Although MVC is not required, I would like to show how easy it is to integrate.

Why do we need scheduling?
Scheduling is needed if you want to automate the repetition of a task at specific intervals or particular date. You could of course manually watch the time and execute your task, albeit an inefficient task. Who wants to watch the computer every 3 seconds just to hit the Enter key? No one.

The work
We want to run the following sample class at specific intervals:

The task that we're interested is inside the work() method. This example is based on Mark Fisher's example at Task Scheduling Simplifications in Spring 3.0. This method retrieves the thread name, prints the starting and beginning of the method, simulates work by putting the thread in sleep for 10 seconds.

To schedule this using Quartz, we'll do it in two ways via the JobDetailBean and via the MethodInvokingJobDetailFactoryBean.

MethodInvokingJobDetailFactoryBean
The MethodInvokingJobDetailFactoryBean is the simpler of the two, albeit simple options. So we'll start with that.

Using the MethodInvokingJobDetailFactoryBean
Often you just need to invoke a method on a specific object. Using the MethodInvokingJobDetailFactoryBean you can do exactly this.... Using the MethodInvokingJobDetailFactoryBean, you don't need to create one-line jobs that just invoke a method, and you only need to create the actual business object and wire up the detail object.

Source: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html
Let's examine an actual example. We'll create a new class SyncWorker that implements a Worker interface.

Worker

SyncWorker

This worker is synchronous which means if we have to call this worker 10 times, it will block the other workers. They cannot start immediately until the first one is finished. If you like to see an example of asynchronous scheduling, please see Spring 3 - Task Scheduling via Annotations: @Scheduled, @Async

To run this using the MethodInvokingJobDetailFactoryBean, we need to declare it in an XML configuration:

quartz-job.xml

We have declared our SyncWorker as a simple bean:

Then we made a reference to our worker inside a MethodInvokingJobDetailFactoryBean. On the targetMethod property, we assign the method name work() that needs to be scheduled.

In order for this to be triggered, we need a Trigger.

This trigger runs every 10 seconds, with a starting delay of 10 seconds as well.
In order for this trigger to be managed, we need a Scheduler
The SchedulerFactoryBean purpose is to schedule the actual jobs assigned in the triggers. You may wonder why we need to have a scheduler, a trigger, and a job just to schedule a single task in Quartz?
Quartz uses Trigger, Job and JobDetail objects to realize scheduling of all kinds of jobs. For the basic concepts behind Quartz, have a look at http://www.opensymphony.com/quartz. For convenience purposes, Spring offers a couple of classes that simplify the usage of Quartz within Spring-based applications. Source: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html
Let's run the application and see the output on the logs:
Notice how our worker is executed. It runs synchronously as expected. The numbers in Worker-1, Worker-2, and etc represents the thread ppol. Our max Worker is 10, so we have a pool size of 10. To modify this value, add the following quartzProperties in the SchedulerFactoryBean:

JobDetailBean
Let's explore another way of scheduling using Quartz. We'll use the JobDetailBean.

What is a JobDetailBean
Convenience subclass of Quartz's JobDetail class, making bean-style usage easier.

JobDetail itself is already a JavaBean but lacks sensible defaults. This class uses the Spring bean name as job name, and the Quartz default group ("DEFAULT") as job group if not specified.

Source: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/scheduling/quartz/JobDetailBean.html
Let's examine an actual example. We'll create a custom class CustomJob that extends QuartzJobBean and implements StatefulJob

CustomJob

Notice our worker is a normal private field. We have assigned a setter method for this worker.

This is required so that Spring can inject the value from the XML configuration. Our worker is executed inside the executeInternal() method:

You can access various details of your job via the JobExecutionContext.

To activate our CustomJob, we need to enable it in the XML configuration.

quartz-job.xml

The configuration is similar with our first example using MethodInvokingJobDetailFactoryBean. The main difference here is we're using aJobDetailBean

We're also using a CronTrigger. Nonetheless, the idea is similar with our initial example.

Let's run our application and see the output:

Same result. We just have more logs because of the CustomJob.

That's it. We've added scheduling support using the Quartz Scheduler. We've used two support beans to realize our goal. Feel free to modify the MVC app to fit your needs. You might wanna try integrating a web service with scheduling and show the results via MVC. The welcome page is accesible at
http://localhost:8080/spring-mvc-quartz-scheduling/krams/main/welcome
The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-mvc-scheduling/

You can download the project as a Maven build. Look for the spring-mvc-quartz-scheduling.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you need to know more about Task Scheduling in Spring 3.0, please visit the following links:

StumpleUpon DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google I'm reading: Spring 3 - Quartz Scheduling ~ Twitter FaceBook

Subscribe by reader Subscribe by email Share

17 comments:

  1. very good article, I was able to work on it and understand the basics of spring + quartz integration. Thanks

    -prakash
    UC Davis

    ReplyDelete
  2. Thank you for sharing this, it was very helpful.

    I did following changes to dependency scopes get your maven project working on JBoss 6.

    junit -> test
    quartz -> provided (version 1.8.3)
    (jstl, taglibs -> removed entirely.)

    ReplyDelete
  3. Thank you for this post, it's very useful.

    Is there any elegant way to extract and store the trigger parameters in the DB instead of configuration file?

    It makes more sense to me having it that way for enterprise apps, since it provides you the ability to control everything from one central place and also allow you to support LB easily.

    Thanks,
    John

    ReplyDelete
    Replies
    1. You might want to look at this thread http://forum.springsource.org/showthread.php?99309-Spring-and-Quartz-can-t-update-Triggers and this http://stackoverflow.com/questions/1187882/quartz-jobstore-with-spring-framework

      Send me a message if these do help :-)

      Delete
  4. Useful post, I have a question though:

    If I am just playing with very small data and want to schedule some operations, should I stick with spring + quartz OR think of spring batch + quartz. What value add will Spring Batch give me?

    Thanks in advance

    ReplyDelete
  5. Hi Krams,

    What would be the best approach if you want to have multiple webapplications deployed on the same jboss node to share the quartz scheduler ?

    Regards,
    Rips

    ReplyDelete
  6. Hi,
    Very good article, thanks for sharing. I am trying to use Quartz 2.1 with Spring 3.0. In this persistence not working. In my configuration I used the same transaction manager (which I used for my UI tasks) for quartz jobs also, but failed.
    Steps in my Job
    1) Retrieve data from tables (Parent and child).
    2) Manipulate and tried to update data in both tables.
    3) Parent update success, but child failed. Here the data in parent does not got rollback.

    Why my transaction manager not worked. Please suggest me if there are any workaround regarding this.

    thanks & regards,
    Mangapathi

    ReplyDelete
  7. Good one!! Its simple and effective.

    I have a requirement, where the crontrigger parameters can be changed from GUI and based on the configured values, I should schedule the job. Can you give any pointers to this ? How to configure the trigger parameters dynamically without configuring in the XML ?

    ReplyDelete
  8. Hi Krams,

    Thanks very much! it helped a lot.

    ReplyDelete
  9. Hi Krams, I appreciate all these , you are a nice person, we are always learning from you, you give all what you know.

    How to integrate spring Quartz + spring MVC, so we can monitor jobs or tasks in jsp page instead of runing main java application ?
    thanks lot.

    ReplyDelete
  10. Hi krams,
    how can this system handle misfire. For example, if the stystem get shut down and on restart how can we make the system trigger the job which was not done.
    However, the exmaple you have provided is really good.
    thanks a lot

    ReplyDelete
  11. Kiến thức của tác giả quá hay, cám ơn bạn đã chia sẻ.
    Thông tin thêm : Thạch anh vụn dải bể cá

    ReplyDelete
  12. Bài post của tác giả rất hữu ích, cám ơn bạn đã share.
    Page hữu ích : Thiềm thừ

    ReplyDelete
  13. I have read your blog its very attractive and impressive. I like it your blog.

    Spring online training Spring online training Spring Hibernate online training Spring Hibernate online training Java online training

    spring training in chennai spring hibernate training in chennai

    ReplyDelete
  14. Happy to found this blog. Good Post!. It was so good to read and useful to improve my knowledge as updated one, keep blogging. Hibernate Training in Electronic City
    Java Training in Electronic City

    ReplyDelete