In addition to the TaskExecutor
abstraction, Spring 3.0 introduces a TaskScheduler
with a variety of methods for scheduling tasks to run at some point in the future.
public interface TaskScheduler { ScheduledFuture schedule(Runnable task, Trigger trigger); ScheduledFuture schedule(Runnable task, Date startTime); ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period); ScheduledFuture scheduleAtFixedRate(Runnable task, long period); ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay); ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay); }
The simplest method is the one named 'schedule' that takes a
Runnable
and Date
only. That will cause the task to run once after the specified time. All of
the other methods are capable of scheduling tasks to run repeatedly. The
fixed-rate and fixed-delay methods are for simple, periodic execution, but
the method that accepts a Trigger is much more flexible.
The Trigger
interface is
essentially inspired by JSR-236, which, as of Spring 3.0, has not yet
been officially implemented. The basic idea of the
Trigger
is that execution times may be
determined based on past execution outcomes or even arbitrary
conditions. If these determinations do take into account the outcome of
the preceding execution, that information is available within a
TriggerContext
. The
Trigger
interface itself is quite
simple:
public interface Trigger { Date nextExecutionTime(TriggerContext triggerContext); }
As you can see, the TriggerContext
is the most important part. It encapsulates all of the relevant data,
and is open for extension in the future if necessary. The
TriggerContext
is an interface (a
SimpleTriggerContext
implementation is used by
default). Here you can see what methods are available for
Trigger
implementations.
public interface TriggerContext { Date lastScheduledExecutionTime(); Date lastActualExecutionTime(); Date lastCompletionTime(); }
Spring provides two implementations of the
Trigger
interface. The most interesting
one is the CronTrigger
. It enables the
scheduling of tasks based on cron expressions. For example the
following task is being scheduled to run 15 minutes past each hour but
only during the 9-to-5 "business hours" on weekdays.
scheduler.schedule(task, new CronTrigger("* 15 9-17 * * MON-FRI"));
The other out-of-the-box implementation is a
PeriodicTrigger
that accepts a fixed period, an
optional initial delay value, and a boolean to indicate whether the
period should be interpreted as a fixed-rate or a fixed-delay. Since
the TaskScheduler
interface already
defines methods for scheduling tasks at a fixed-rate or with a
fixed-delay, those methods should be used directly whenever possible.
The value of the PeriodicTrigger
implementation
is that it can be used within components that rely on the
Trigger
abstraction. For example, it may
be convenient to allow periodic triggers, cron-based triggers, and even
custom trigger implementations to be used interchangeably. Such a
component could take advantage of dependency injection so that such
Triggers
could be configured externally.
As with Spring's TaskExecutor
abstraction, the primary benefit of the
TaskScheduler
is that code relying on
scheduling behavior need not be coupled to a particular scheduler
implementation. The flexibility this provides is particularly relevant
when running within Application Server environments where threads
should not be created directly by the application itself. For such
cases, Spring provides a
TimerManagerTaskScheduler
that delegates to a
CommonJ TimerManager instance, typically configured with a JNDI-lookup.
A simpler alternative, the
ThreadPoolTaskScheduler
, can be used whenever
external thread management is not a requirement. Internally, it
delegates to a ScheduledExecutorService
instance. ThreadPoolTaskScheduler
actually
implements Spring's TaskExecutor
interface as well, so that a single instance can be used for
asynchronous execution as soon as possible as well
as scheduled, and potentially recurring, executions.