Some Java EE applications may needs to schedule tasks in order to get notified at certain times (i.e. every other Thursday, but only after 10 am and before 2 pm). This should be done in a consistent manner, using either a cron expression, an interval, or a rate. There are several way to do this, from EJB timer service introduced with EJB 3.1 to framework like Quartz.
Let’s assume that we are developing our application on Spring framework. Spring 3.0 debuts new support for configuring TaskExecutors and TaskSchedulers. This capability, coupled with the ability to schedule method execution using the @Scheduled annotation, makes Spring 3.0 very capable of meeting this challenge. The scheduling support works with a minimal of fuss: all you need are a method, an annotation, and to have switched on the scanner for annotations, in the simplest case.
This article will show you how to implement a simple application that periodically print “Hello world”, just using Spring’s capabilities.
1 The POM file
We just need of this dependancy:
<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>org.madbit.spring</groupId> <artifactId>spring-schedule</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.1.1.RELEASE</version> </dependency> </dependencies> </project>
2 Periodic Task class
Here the code of the class which implements the task that we want schedule periodically.
package org.madbit.spring.periodic; public class PeriodicTask { public synchronized void execute() { System.out.println("Hello world"); } }
3 Spring configuration
Spring supports three ways of schedule task:
- fixedDelay: value measured from the completion time of the previous invocation
- fixedRate: value measure the time between successive starts and then trigger another run
- cron: execution of the method based on cron expression
In the following configuration file (periodicTasks.xml) we can find the spring scheduler and executor declaration, the periodicTask bean related to our class. At the end that file is passed to the scheduler in the three different ways described before. In this way three different tasks will be scheduled based on their declarations.
<?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" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd"> <task:scheduler id="scheduler" pool-size="10"/> <task:executor id="executor" pool-size="10"/> <task:annotation-driven scheduler="scheduler" executor="executor"/> <bean id="periodicTask" class="org.madbit.spring.periodic.PeriodicTask" /> <task:scheduled-tasks scheduler="scheduler"> <task:scheduled ref="periodicTask" method="execute" fixed-rate="60000"/> <task:scheduled ref="periodicTask" method="execute" fixed-delay="60000"/> <task:scheduled ref="periodicTask" method="execute" cron="*/5 * * * * ?"/> </task:scheduled-tasks> </beans>
For fixed-rate and fixed-delay the specified value is in milliseconds. For the cron case, the meaning of the fields is reported in the following table:
Position | Field Name | Range |
1 | Second | 0–59 |
2 | Minute | 0–59 |
3 | Hour | 0–23 |
4 | Day of month | 1–31 |
5 | Month | 1–12 or JAN–DEC |
6 | Day of week | 1–7 or SUN–SAT |
7 | Year (optional) | 1970–2099 |
4 Run the application
Below a simple Main class that initialize the application context from the configuration file periodicTasks.xml. After the context is initialized, the task will start to be scheduled.
package org.madbit.spring.periodic; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main { public static void main(String[] args) { new ClassPathXmlApplicationContext("periodicTasks.xml"); } }
5 Using annotation
Alternatively it’s possible annotate methods to schedule directly in the classes in the following way:
package org.madbit.spring.periodic; import org.springframework.scheduling.annotation.Scheduled; public class PeriodicTask { @Scheduled(fixedRate = 60 * 1000) public synchronized void execute() { System.out.println("Hello world"); } }
In this case you don’t need to define any task stuff in the Spring configuration file. You just need to define the periodic task bean and enable the component scan, specifying the package that contains the class.
<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" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd"> <context:component-scan annotation-config="true" base-package="org.madbit.spring.periodic"/> <task:scheduler id="scheduler" pool-size="10"/> <task:executor id="executor" pool-size="10"/> <task:annotation-driven scheduler="scheduler" executor="executor"/> <bean id="periodicTask" class="org.madbit.spring.periodic.PeriodicTask" /> </beans>