Matt Young

02/23/2010

Scheduled Jobs in Spring 3

Matt Young // in Technology

Spring has made scheduling a Java method as easy as creating a UNIX cron job. Here's a quick introduction.

Those of us who got our start writing web applications in the early days were used to having cron available to us to run PERL scripts when we needed a periodic task executed. Over time, the evolution of web applications into the application server space has made it a little less convenient to run your business logic at an appropriate interval. 

Within the Java world, Quartz is a commonly used technology introduced to solve the problem.

But the people behind Spring have, as with most things, boiled the process down to something very simple.

Spring 2 had a useful task executor and task scheduler, but Spring 3 has evolved the process into easy annotation-based awesomeness. Java methods that you've already written to generate reports, do maintenance, or check status can all be run with common cron interval definitions.

Here's a quick set of steps you can use to set up this kind of scheduled task within your Spring-based Java application:

Step 1: Define a task executor and task scheduler in an application context file:

<?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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd">
<task:scheduler id="taskScheduler"/>
<task:executor id="taskExecutor" pool-size="1"/>
<task:annotation-driven executor="taskExecutor" scheduler="taskScheduler"/>
</beans>

The "task" namespace is used here to declare the scheduler and executor. The third line of the XML asks Spring to scan classes for annotations related to scheduled tasks. If you have multiple tasks to run at the same time, you can get them to run in parallel by increasing the pool size.

Step 2: Annotate the method you want to run on a schedule

@Service
public class ReportingServiceImpl implements ReportingService {
private static final Logger logger = Logger.getLogger(ReportingServiceImpl.class);
@Autowired
private MailService ms;
@Override
// Every night at 1 AM
@Scheduled(cron = "* * 1 * * ?")
public void generateAndEmailReport() {
logger.info("Starting report at " + new Date(System.currentTimeMillis()));
Report r = generateReport();
ms.sendReport(r);
logger.info("Report sent at " + new Date(System.currentTimeMillis()));
}
}

 

Simple!

There are some other useful variants of the annotations. Instead of supplying a 'cron' pattern, you could just define an interval.

@Scheduled(fixedRate=60000)

This annotation would have a method run every 60 seconds. (FixedRate defines a time in milliseconds)

You can also use the

@Async

annotation to mark a scheduled method as asynchronous.

Two things to be aware of:

At the time of writing, there's no way to control if or how often a method is retried if an exception occurs during scheduled method execution. So, if an exception happens during execution of a scheduled method, Spring will re-try the method automatically. If the exception continues to happen, this can result in large logs and possibly a lot of resource consumption. I've submitted an enhancement request to Spring to make this behavior configurable. http://jira.springframework.org/browse/SPR-6860

Spring 3.0.0 Release had a bug where web apps with a task scheduler would end up executing scheduled methods twice. This has been resolved in Spring 3.0.1.

You can read more about scheduling tasks with Spring here: http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/scheduling.html

 

READ MORE.

 

Share Article