933 lines
42 KiB
XML
933 lines
42 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
|
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
|
<chapter id="scheduling">
|
|
<title>Task Execution and Scheduling</title>
|
|
|
|
<section id="scheduling-introduction">
|
|
<title>Introduction</title>
|
|
|
|
<para>The Spring Framework provides abstractions for asynchronous
|
|
execution and scheduling of tasks with the
|
|
<interfacename>TaskExecutor</interfacename> and
|
|
<interfacename>TaskScheduler</interfacename> interfaces, respectively.
|
|
Spring also features implementations of those interfaces that support
|
|
thread pools or delegation to CommonJ within an application server
|
|
environment. Ultimately the use of these implementations behind the common
|
|
interfaces abstracts away the differences between Java SE 5, Java SE 6 and
|
|
Java EE environments.</para>
|
|
|
|
<para>Spring also features integration classes for supporting scheduling
|
|
with the <classname>Timer</classname>, part of the JDK since 1.3, and the
|
|
Quartz Scheduler (<ulink
|
|
url="http://www.opensymphony.com/quartz/"></ulink>). Both of those
|
|
schedulers are set up using a <interfacename>FactoryBean</interfacename>
|
|
with optional references to <classname>Timer</classname> or
|
|
<classname>Trigger</classname> instances, respectively. Furthermore, a
|
|
convenience class for both the Quartz Scheduler and the
|
|
<classname>Timer</classname> is available that allows you to invoke a
|
|
method of an existing target object (analogous to the normal
|
|
<classname>MethodInvokingFactoryBean</classname> operation).</para>
|
|
</section>
|
|
|
|
<section id="scheduling-task-executor">
|
|
<title>The Spring <interfacename>TaskExecutor</interfacename>
|
|
abstraction</title>
|
|
|
|
<para>Spring 2.0 introduces a new abstraction for dealing with executors.
|
|
Executors are the Java 5 name for the concept of thread pools. The
|
|
"executor" naming is due to the fact that there is no guarantee that the
|
|
underlying implementation is actually a pool; an executor may be
|
|
single-threaded or even synchronous. Spring's abstraction hides
|
|
implementation details between Java SE 1.4, Java SE 5 and Java EE
|
|
environments.</para>
|
|
|
|
<para>Spring's <interfacename>TaskExecutor</interfacename> interface is
|
|
identical to the <classname>java.util.concurrent.Executor</classname>
|
|
interface. In fact, its primary reason for existence is to abstract away
|
|
the need for Java 5 when using thread pools. The interface has a single
|
|
method <classname>execute(Runnable task)</classname> that accepts a task
|
|
for execution based on the semantics and configuration of the thread
|
|
pool.</para>
|
|
|
|
<para>The <interfacename>TaskExecutor</interfacename> was originally
|
|
created to give other Spring components an abstraction for thread pooling
|
|
where needed. Components such as the
|
|
<classname>ApplicationEventMulticaster</classname>, JMS's
|
|
<classname>AbstractMessageListenerContainer</classname>, and Quartz
|
|
integration all use the <interfacename>TaskExecutor</interfacename>
|
|
abstraction to pool threads. However, if your beans need thread pooling
|
|
behavior, it is possible to use this abstraction for your own
|
|
needs.</para>
|
|
|
|
<section id="scheduling-task-executor-types">
|
|
<title><interfacename>TaskExecutor</interfacename> types</title>
|
|
|
|
<para>There are a number of pre-built implementations of
|
|
<interfacename>TaskExecutor</interfacename> included with the Spring
|
|
distribution. In all likelihood, you shouldn't ever need to implement
|
|
your own.</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para><classname>SimpleAsyncTaskExecutor</classname></para>
|
|
|
|
<para>This implementation does not reuse any threads, rather it
|
|
starts up a new thread for each invocation. However, it does support
|
|
a concurrency limit which will block any invocations that are over
|
|
the limit until a slot has been freed up. If you're looking for true
|
|
pooling, keep scrolling further down the page.</para>
|
|
</listitem>
|
|
|
|
<listitem id="syncTaskExecutor">
|
|
<para><classname>SyncTaskExecutor</classname></para>
|
|
|
|
<para>This implementation doesn't execute invocations
|
|
asynchronously. Instead, each invocation takes place in the calling
|
|
thread. It is primarily used in situations where multithreading
|
|
isn't necessary such as simple test cases.</para>
|
|
</listitem>
|
|
|
|
<listitem id="concurrentTaskExecutor">
|
|
<para><classname>ConcurrentTaskExecutor</classname></para>
|
|
|
|
<para>This implementation is a wrapper for a Java 5
|
|
<classname>java.util.concurrent.Executor</classname>. There is an
|
|
alternative, <classname>ThreadPoolTaskExecutor</classname>, that
|
|
exposes the <classname>Executor</classname> configuration parameters
|
|
as bean properties. It is rare to need to use the
|
|
<classname>ConcurrentTaskExecutor</classname> but if the <link
|
|
linkend="threadPoolTaskExecutor"><classname>ThreadPoolTaskExecutor</classname></link>
|
|
isn't robust enough for your needs, the
|
|
<classname>ConcurrentTaskExecutor</classname> is an
|
|
alternative.</para>
|
|
</listitem>
|
|
|
|
<listitem id="simpleThreadPoolTaskExecutor">
|
|
<para><classname>SimpleThreadPoolTaskExecutor</classname></para>
|
|
|
|
<para>This implementation is actually a subclass of Quartz's
|
|
<classname>SimpleThreadPool</classname> which listens to Spring's
|
|
lifecycle callbacks. This is typically used when you have a thread
|
|
pool that may need to be shared by both Quartz and non-Quartz
|
|
components.</para>
|
|
</listitem>
|
|
|
|
<listitem id="threadPoolTaskExecutor">
|
|
<para><classname>ThreadPoolTaskExecutor</classname></para>
|
|
|
|
<sidebar>
|
|
<para>It is not possible to use any backport or alternate versions
|
|
of the <classname>java.util.concurrent</classname> package with
|
|
this implementation. Both Doug Lea's and Dawid Kurzyniec's
|
|
implementations use different package structures which will
|
|
prevent them from working correctly.</para>
|
|
</sidebar>
|
|
|
|
<para>This implementation can only be used in a Java 5 environment
|
|
but is also the most commonly used one in that environment. It
|
|
exposes bean properties for configuring a
|
|
<classname>java.util.concurrent.ThreadPoolExecutor</classname> and
|
|
wraps it in a <interfacename>TaskExecutor</interfacename>. If you
|
|
need something advanced such as a
|
|
<classname>ScheduledThreadPoolExecutor</classname>, it is
|
|
recommended that you use a <link
|
|
linkend="concurrentTaskExecutor"><classname>ConcurrentTaskExecutor</classname></link>
|
|
instead.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><classname>TimerTaskExecutor</classname></para>
|
|
|
|
<para>This implementation uses a single
|
|
<classname>TimerTask</classname> as its backing implementation. It's
|
|
different from the <link
|
|
linkend="syncTaskExecutor"><classname>SyncTaskExecutor</classname></link>
|
|
in that the method invocations are executed in a separate thread,
|
|
although they are synchronous in that thread.</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para><classname>WorkManagerTaskExecutor</classname></para>
|
|
|
|
<sidebar>
|
|
<para>CommonJ is a set of specifications jointly developed between
|
|
BEA and IBM. These specifications are not Java EE standards, but
|
|
are standard across BEA's and IBM's Application Server
|
|
implementations.</para>
|
|
</sidebar>
|
|
|
|
<para>This implementation uses the CommonJ WorkManager as its
|
|
backing implementation and is the central convenience class for
|
|
setting up a CommonJ WorkManager reference in a Spring context.
|
|
Similar to the <link
|
|
linkend="simpleThreadPoolTaskExecutor"><classname>SimpleThreadPoolTaskExecutor</classname></link>,
|
|
this class implements the WorkManager interface and therefore can be
|
|
used directly as a WorkManager as well.</para>
|
|
</listitem>
|
|
</itemizedlist>
|
|
</section>
|
|
|
|
<section id="scheduling-task-executor-usage">
|
|
<title>Using a <interfacename>TaskExecutor</interfacename></title>
|
|
|
|
<para>Spring's <interfacename>TaskExecutor</interfacename>
|
|
implementations are used as simple JavaBeans. In the example below, we
|
|
define a bean that uses the
|
|
<classname>ThreadPoolTaskExecutor</classname> to asynchronously print
|
|
out a set of messages.</para>
|
|
|
|
<programlisting language="java">import org.springframework.core.task.TaskExecutor;
|
|
|
|
public class TaskExecutorExample {
|
|
|
|
private class MessagePrinterTask implements Runnable {
|
|
|
|
private String message;
|
|
|
|
public MessagePrinterTask(String message) {
|
|
this.message = message;
|
|
}
|
|
|
|
public void run() {
|
|
System.out.println(message);
|
|
}
|
|
|
|
}
|
|
|
|
private TaskExecutor taskExecutor;
|
|
|
|
public TaskExecutorExample(TaskExecutor taskExecutor) {
|
|
this.taskExecutor = taskExecutor;
|
|
}
|
|
|
|
public void printMessages() {
|
|
for(int i = 0; i < 25; i++) {
|
|
taskExecutor.execute(new MessagePrinterTask("Message" + i));
|
|
}
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>As you can see, rather than retrieving a thread from the pool and
|
|
executing yourself, you add your <classname>Runnable</classname> to the
|
|
queue and the <interfacename>TaskExecutor</interfacename> uses its
|
|
internal rules to decide when the task gets executed.</para>
|
|
|
|
<para>To configure the rules that the
|
|
<interfacename>TaskExecutor</interfacename> will use, simple bean
|
|
properties have been exposed.</para>
|
|
|
|
<programlisting language="xml"><bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
|
|
<property name="corePoolSize" value="5" />
|
|
<property name="maxPoolSize" value="10" />
|
|
<property name="queueCapacity" value="25" />
|
|
</bean>
|
|
|
|
<bean id="taskExecutorExample" class="TaskExecutorExample">
|
|
<constructor-arg ref="taskExecutor" />
|
|
</bean></programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="scheduling-task-scheduler">
|
|
<title>The Spring <interfacename>TaskScheduler</interfacename>
|
|
abstraction</title>
|
|
|
|
<para>In addition to the <interfacename>TaskExecutor</interfacename>
|
|
abstraction, Spring 3.0 introduces a
|
|
<interfacename>TaskScheduler</interfacename> with a variety of methods for
|
|
scheduling tasks to run at some point in the future.</para>
|
|
|
|
<programlisting language="java">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);
|
|
|
|
}</programlisting>
|
|
|
|
<para>The simplest method is the one named 'schedule' that takes a
|
|
<interfacename>Runnable</interfacename> and <classname>Date</classname>
|
|
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.</para>
|
|
|
|
<section id="scheduling-trigger-interface">
|
|
<title>The <interfacename>Trigger</interfacename> interface</title>
|
|
|
|
<para>The <interfacename>Trigger</interfacename> interface is
|
|
essentially inspired by JSR-236, which, as of Spring 3.0, has not yet
|
|
been officially implemented. The basic idea of the
|
|
<interfacename>Trigger</interfacename> 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
|
|
<interfacename>TriggerContext</interfacename>. The
|
|
<interfacename>Trigger</interfacename> interface itself is quite
|
|
simple:</para>
|
|
|
|
<programlisting language="java">public interface Trigger {
|
|
|
|
Date nextExecutionTime(TriggerContext triggerContext);
|
|
|
|
}</programlisting>
|
|
|
|
<para>As you can see, the <interfacename>TriggerContext</interfacename>
|
|
is the most important part. It encapsulates all of the relevant data,
|
|
and is open for extension in the future if necessary. The
|
|
<interfacename>TriggerContext</interfacename> is an interface (a
|
|
<classname>SimpleTriggerContext</classname> implementation is used by
|
|
default). Here you can see what methods are available for
|
|
<interfacename>Trigger</interfacename> implementations.</para>
|
|
|
|
<programlisting language="java">public interface TriggerContext {
|
|
|
|
Date lastScheduledExecutionTime();
|
|
|
|
Date lastActualExecutionTime();
|
|
|
|
Date lastCompletionTime();
|
|
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="scheduling-trigger-implementations">
|
|
<title><interfacename>Trigger</interfacename> implementations</title>
|
|
|
|
<para>Spring provides two implementations of the
|
|
<interfacename>Trigger</interfacename> interface. The most interesting
|
|
one is the <classname>CronTrigger</classname>. 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.</para>
|
|
|
|
<programlisting language="java">scheduler.schedule(task, new CronTrigger("* 15 9-17 * * MON-FRI"));</programlisting>
|
|
|
|
<para>The other out-of-the-box implementation is a
|
|
<classname>PeriodicTrigger</classname> 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
|
|
<interfacename>TaskScheduler</interfacename> 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 <classname>PeriodicTrigger</classname> implementation is that it can
|
|
be used within components that rely on the
|
|
<interfacename>Trigger</interfacename> 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
|
|
<interfacename>Triggers</interfacename> could be configured
|
|
externally.</para>
|
|
</section>
|
|
|
|
<section id="scheduling-task-scheduler-implementations">
|
|
<title><interfacename>TaskScheduler</interfacename>
|
|
implementations</title>
|
|
|
|
<para>As with Spring's <interfacename>TaskExecutor</interfacename>
|
|
abstraction, the primary benefit of the
|
|
<interfacename>TaskScheduler</interfacename> 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 <classname>TimerManagerTaskScheduler</classname> that
|
|
delegates to a CommonJ TimerManager instance, typically configured with
|
|
a JNDI-lookup.</para>
|
|
|
|
<para>A simpler alternative, the
|
|
<classname>ThreadPoolTaskScheduler</classname>, can be used whenever
|
|
external thread management is not a requirement. Internally, it
|
|
delegates to a <interfacename>ScheduledExecutorService</interfacename>
|
|
instance. <classname>ThreadPoolTaskScheduler</classname> actually
|
|
implements Spring's <interfacename>TaskExecutor</interfacename>
|
|
interface as well, so that a single instance can be used for
|
|
asynchronous execution <emphasis>as soon as possible</emphasis> as well
|
|
as scheduled, and potentially recurring, executions.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="scheduling-task-namespace">
|
|
<title>The Task Namespace</title>
|
|
|
|
<para>Beginning with Spring 3.0, there is an XML namespace for configuring
|
|
<interfacename>TaskExecutor</interfacename> and
|
|
<interfacename>TaskScheduler</interfacename> instances. It also provides a
|
|
convenient way to configure tasks to be scheduled with a trigger.</para>
|
|
|
|
<section id="scheduling-task-namespace-scheduler">
|
|
<title>The 'scheduler' element</title>
|
|
|
|
<para>The following element will create a
|
|
<classname>ThreadPoolTaskScheduler</classname> instance with the
|
|
specified thread pool size.</para>
|
|
|
|
<programlisting language="xml"><task:scheduler id="scheduler" pool-size="10"/></programlisting>
|
|
|
|
<para>The value provided for the 'id' attribute will be used as the
|
|
prefix for thread names within the pool. The 'scheduler' element is
|
|
relatively straightforward. If you do not provide a 'pool-size'
|
|
attribute, the default thread pool will only have a single thread. There
|
|
are no other configuration options for the scheduler.</para>
|
|
</section>
|
|
|
|
<section id="scheduling-task-namespace-executor">
|
|
<title>The 'executor' element</title>
|
|
|
|
<para>The following will create a
|
|
<classname>ThreadPoolTaskExecutor</classname> instance: <programlisting
|
|
language="xml"><task:executor id="executor" pool-size="10"/></programlisting></para>
|
|
|
|
<para>As with the scheduler above, the value provided for the 'id'
|
|
attribute will be used as the prefix for thread names within the pool.
|
|
As far as the pool size is concerned, the 'executor' element supports
|
|
more configuration options than the 'scheduler' element. For one thing,
|
|
the thread pool for a <classname>ThreadPoolTaskExecutor</classname> is
|
|
itself more configurable. Rather than just a single size, an executor's
|
|
thread pool may have different values for the <emphasis>core</emphasis>
|
|
and the <emphasis>max</emphasis> size. If a single value is provided
|
|
then the executor will have a fixed-size thread pool (the core and max
|
|
sizes are the same). However, the 'executor' element's 'pool-size'
|
|
attribute also accepts a range in the form of "min-max". <programlisting
|
|
language="xml"><task:executor id="executorWithPoolSizeRange"
|
|
pool-size="5-25"
|
|
queue-capacity="100"/></programlisting></para>
|
|
|
|
<para>As you can see from that configuration, a 'queue-capacity' value
|
|
has also been provided. The configuration of the thread pool should also
|
|
be considered in light of the executor's queue capacity. For the full
|
|
description of the relationship between pool size and queue capacity,
|
|
consult the documentation for <ulink
|
|
url="http://java.sun.com/javase/6/docs/api/java/util/concurrent/ThreadPoolExecutor.html">ThreadPoolExecutor</ulink>.
|
|
The main idea is that when a task is submitted, the executor will first
|
|
try to use a free thread if the number of active threads is currently
|
|
less than the core size. If the core size has been reached, then the
|
|
task will be added to the queue as long as its capacity has not yet been
|
|
reached. Only then, if the queue's capacity <emphasis>has</emphasis>
|
|
been reached, will the executor create a new thread beyond the core
|
|
size. If the max size has also been reached, then the executor will
|
|
reject the task.</para>
|
|
|
|
<para>By default, the queue is <emphasis>unbounded</emphasis>, but this
|
|
is rarely the desired configuration, because it can lead to
|
|
<classname>OutOfMemoryErrors</classname> if enough tasks are added to
|
|
that queue while all pool threads are busy. Furthermore, if the queue is
|
|
unbounded, then the max size has no effect at all. Since the executor
|
|
will always try the queue before creating a new thread beyond the core
|
|
size, a queue must have a finite capacity for the thread pool to grow
|
|
beyond the core size (this is why a <emphasis>fixed size</emphasis> pool
|
|
is the only sensible case when using an unbounded queue).</para>
|
|
|
|
<para>In a moment, we will review the effects of the keep-alive setting
|
|
which adds yet another factor to consider when providing a pool size
|
|
configuration. First, let's consider the case, as mentioned above, when
|
|
a task is rejected. By default, when a task is rejected, a thread pool
|
|
executor will throw a <classname>TaskRejectedException</classname>.
|
|
However, the rejection policy is actually configurable. The exception is
|
|
thrown when using the default rejection policy which is the
|
|
<classname>AbortPolicy</classname> implementation. For applications
|
|
where some tasks can be skipped under heavy load, either the
|
|
<classname>DiscardPolicy</classname> or
|
|
<classname>DiscardOldestPolicy</classname> may be configured instead.
|
|
Another option that works well for applications that need to throttle
|
|
the submitted tasks under heavy load is the
|
|
<classname>CallerRunsPolicy</classname>. Instead of throwing an
|
|
exception or discarding tasks, that policy will simply force the thread
|
|
that is calling the submit method to run the task itself. The idea is
|
|
that such a caller will be busy while running that task and not able to
|
|
submit other tasks immediately. Therefore it provides a simple way to
|
|
throttle the incoming load while maintaining the limits of the thread
|
|
pool and queue. Typically this allows the executor to "catch up" on the
|
|
tasks it is handling and thereby frees up some capacity on the queue, in
|
|
the pool, or both. Any of these options can be chosen from an
|
|
enumeration of values available for the 'rejection-policy' attribute on
|
|
the 'executor' element.</para>
|
|
|
|
<programlisting language="xml"><task:executor id="executorWithCallerRunsPolicy"
|
|
pool-size="5-25"
|
|
queue-capacity="100"
|
|
rejection-policy="CALLER_RUNS"/></programlisting>
|
|
</section>
|
|
|
|
<section id="scheduling-task-namespace-scheduled-tasks">
|
|
<title>The 'scheduled-tasks' element</title>
|
|
|
|
<para>The most powerful feature of Spring's task namespace is the
|
|
support for configuring tasks to be scheduled within a Spring
|
|
Application Context. This follows an approach similar to other
|
|
"method-invokers" in Spring, such as that provided by the JMS namespace
|
|
for configuring Message-driven POJOs. Basically a "ref" attribute can
|
|
point to any Spring-managed object, and the "method" attribute provides
|
|
the name of a method to be invoked on that object. Here is a simple
|
|
example.</para>
|
|
|
|
<programlisting language="xml"><task:scheduled-tasks scheduler="myScheduler">
|
|
<task:scheduled ref="someObject" method="someMethod" fixed-delay="5000"/>
|
|
</task:scheduled-tasks>
|
|
|
|
<task:scheduler id="myScheduler" pool-size="10"/></programlisting>
|
|
|
|
<para>As you can see, the scheduler is referenced by the outer element,
|
|
and each individual task includes the configuration of its trigger
|
|
metadata. In the preceding example, that metadata defines a periodic
|
|
trigger with a fixed delay. It could also be configured with a
|
|
"fixed-rate", or for more control, a "cron" attribute could be provided
|
|
instead. Here's an example featuring these other options.</para>
|
|
|
|
<programlisting language="xml"><task:scheduled-tasks scheduler="myScheduler">
|
|
<task:scheduled ref="someObject" method="someMethod" fixed-rate="5000"/>
|
|
<task:scheduled ref="anotherObject" method="anotherMethod" cron="*/5 * * * * MON-FRI"/>
|
|
</task:scheduled-tasks>
|
|
|
|
<task:scheduler id="myScheduler" pool-size="10"/></programlisting>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="scheduling-annotation-support">
|
|
<title>Annotation Support for Scheduling and Asynchronous
|
|
Execution</title>
|
|
|
|
<para>Spring 3.0 also adds annotation support for both task scheduling and
|
|
asynchronous method execution.</para>
|
|
|
|
<section id="scheduling-annotation-support-scheduled">
|
|
<title>The @Scheduled Annotation</title>
|
|
|
|
<para>The @Scheduled annotation can be added to a method along with
|
|
trigger metadata. For example, the following method would be invoked
|
|
every 5 seconds with a fixed delay, meaning that the period will be
|
|
measured from the completion time of each preceding invocation.</para>
|
|
|
|
<programlisting language="java">@Scheduled(fixedDelay=5000)
|
|
public void doSomething() {
|
|
// something that should execute periodically
|
|
}</programlisting>
|
|
|
|
<para>If a fixed rate execution is desired, simply change the property
|
|
name specified within the annotation. The following would be executed
|
|
every 5 seconds measured between the successive start times of each
|
|
invocation.</para>
|
|
|
|
<programlisting language="java">@Scheduled(fixedRate=5000)
|
|
public void doSomething() {
|
|
// something that should execute periodically
|
|
}</programlisting>
|
|
|
|
<para>If simple periodic scheduling is not expressive enough, then a
|
|
cron expression may be provided. For example, the following will only
|
|
execute on weekdays.</para>
|
|
|
|
<programlisting language="java">@Scheduled(cron="*/5 * * * * MON-FRI")
|
|
public void doSomething() {
|
|
// something that should execute on weekdays only
|
|
}</programlisting>
|
|
|
|
<para>Notice that the methods to be scheduled must have void returns and
|
|
must not expect any arguments. If the method needs to interact with
|
|
other objects from the Application Context, then those would typically
|
|
have been provided through dependency injection.</para>
|
|
|
|
<note>
|
|
<para>Make sure that you are not initializing multiple instances of
|
|
the same @Scheduled annotation class at runtime, unless you do want to
|
|
schedule callbacks to each such instance. Related to this, make sure
|
|
that you do not use @Configurable on bean classes which are annotated
|
|
with @Scheduled and registered as regular Spring beans with the
|
|
container: You would get double initialization otherwise, once through
|
|
the container and once through the @Configurable aspect, with the
|
|
consequence of each @Scheduled method being invoked twice.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="scheduling-annotation-support-async">
|
|
<title>The @Async Annotation</title>
|
|
|
|
<para>The <interfacename>@Async</interfacename> annotation can be
|
|
provided on a method so that invocation of that method will occur
|
|
asynchronously. In other words, the caller will return immediately upon
|
|
invocation and the actual execution of the method will occur in a task
|
|
that has been submitted to a Spring
|
|
<interfacename>TaskExecutor</interfacename>. In the simplest case, the
|
|
annotation may be applied to a <literal>void</literal>-returning
|
|
method.</para>
|
|
|
|
<programlisting language="java">@Async
|
|
void doSomething() {
|
|
// this will be executed asynchronously
|
|
}</programlisting>
|
|
|
|
<para>Unlike the methods annotated with the
|
|
<interfacename>@Scheduled</interfacename> annotation, these methods can
|
|
expect arguments, because they will be invoked in the "normal" way by
|
|
callers at runtime rather than from a scheduled task being managed by
|
|
the container. For example, the following is a legitimate application of
|
|
the <interfacename>@Async</interfacename> annotation.</para>
|
|
|
|
<programlisting language="java">@Async
|
|
void doSomething(String s) {
|
|
// this will be executed asynchronously
|
|
}</programlisting>
|
|
|
|
<para>Even methods that return a value can be invoked asynchronously.
|
|
However, such methods are required to have a
|
|
<interfacename>Future</interfacename> typed return value. This still
|
|
provides the benefit of asynchronous execution so that the caller can
|
|
perform other tasks prior to calling <methodname>get()</methodname> on
|
|
that Future.</para>
|
|
|
|
<programlisting language="java">@Async
|
|
Future<String> returnSomething(int i) {
|
|
// this will be executed asynchronously
|
|
}</programlisting>
|
|
|
|
<para><interfacename>@Async</interfacename> can not be used in
|
|
conjunction with lifecycle callbacks such as
|
|
<interfacename>@PostConstruct</interfacename>. To asynchonously
|
|
initialize Spring beans you currently have to use a separate
|
|
initializing Spring bean that invokes the
|
|
<interfacename>@Async</interfacename> annotated method on the target
|
|
then.</para>
|
|
|
|
<programlisting language="java">public class SampleBeanImpl implements SampleBean {
|
|
|
|
@Async
|
|
void doSomething() { … }
|
|
}
|
|
|
|
|
|
public class SampleBeanInititalizer {
|
|
|
|
private final SampleBean bean;
|
|
|
|
public SampleBeanInitializer(SampleBean bean) {
|
|
this.bean = bean;
|
|
}
|
|
|
|
@PostConstruct
|
|
public void initialize() {
|
|
bean.doSomething();
|
|
}
|
|
}</programlisting>
|
|
</section>
|
|
|
|
<section id="scheduling-annotation-support-namespace">
|
|
<title>The <annotation-driven> Element</title>
|
|
|
|
<para>To enable both @Scheduled and @Async annotations, simply include
|
|
the 'annotation-driven' element from the task namespace in your
|
|
configuration.</para>
|
|
|
|
<programlisting language="xml"><task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
|
|
|
|
<task:executor id="myExecutor" pool-size="5"/>
|
|
|
|
<task:scheduler id="myScheduler" pool-size="10"/>}</programlisting>
|
|
|
|
<para>Notice that an executor reference is provided for handling those
|
|
tasks that correspond to methods with the @Async annotation, and the
|
|
scheduler reference is provided for managing those methods annotated
|
|
with @Scheduled.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="scheduling-quartz">
|
|
<title>Using the OpenSymphony Quartz Scheduler</title>
|
|
|
|
<para>Quartz uses <classname>Trigger</classname>,
|
|
<classname>Job</classname> and <classname>JobDetail</classname> objects to
|
|
realize scheduling of all kinds of jobs. For the basic concepts behind
|
|
Quartz, have a look at <ulink
|
|
url="http://www.opensymphony.com/quartz"></ulink>. For convenience
|
|
purposes, Spring offers a couple of classes that simplify the usage of
|
|
Quartz within Spring-based applications.</para>
|
|
|
|
<section id="scheduling-quartz-jobdetail">
|
|
<title>Using the JobDetailBean</title>
|
|
|
|
<para><classname>JobDetail</classname> objects contain all information
|
|
needed to run a job. The Spring Framework provides a
|
|
<classname>JobDetailBean</classname> that makes the
|
|
<classname>JobDetail</classname> more of an actual JavaBean with
|
|
sensible defaults. Let's have a look at an example:</para>
|
|
|
|
<programlisting language="xml">
|
|
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean">
|
|
<property name="jobClass" value="example.ExampleJob" />
|
|
<property name="jobDataAsMap">
|
|
<map>
|
|
<entry key="timeout" value="5" />
|
|
</map>
|
|
</property>
|
|
</bean></programlisting>
|
|
|
|
<para>The job detail bean has all information it needs to run the job
|
|
(<classname>ExampleJob</classname>). The timeout is specified in the job
|
|
data map. The job data map is available through the
|
|
<classname>JobExecutionContext</classname> (passed to you at execution
|
|
time), but the <classname>JobDetailBean</classname> also maps the
|
|
properties from the job data map to properties of the actual job. So in
|
|
this case, if the <classname>ExampleJob</classname> contains a property
|
|
named <literal>timeout</literal>, the
|
|
<classname>JobDetailBean</classname> will automatically apply it:</para>
|
|
|
|
<programlisting language="java">package example;
|
|
|
|
public class ExampleJob extends QuartzJobBean {
|
|
|
|
private int timeout;
|
|
|
|
/**
|
|
* Setter called after the ExampleJob is instantiated
|
|
* with the value from the JobDetailBean (5)
|
|
*/
|
|
public void setTimeout(int timeout) {
|
|
this.timeout = timeout;
|
|
}
|
|
|
|
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
|
|
<lineannotation>// do the actual work</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>All additional settings from the job detail bean are of course
|
|
available to you as well.</para>
|
|
|
|
<para><emphasis>Note: Using the <literal>name</literal> and
|
|
<literal>group</literal> properties, you can modify the name and the
|
|
group of the job, respectively. By default, the name of the job matches
|
|
the bean name of the job detail bean (in the example above, this is
|
|
<literal>exampleJob</literal>).</emphasis></para>
|
|
</section>
|
|
|
|
<section id="scheduling-quartz-method-invoking-job">
|
|
<title>Using the
|
|
<classname>MethodInvokingJobDetailFactoryBean</classname></title>
|
|
|
|
<para>Often you just need to invoke a method on a specific object. Using
|
|
the <classname>MethodInvokingJobDetailFactoryBean</classname> you can do
|
|
exactly this:</para>
|
|
|
|
<programlisting language="xml"><bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
|
<property name="targetObject" ref="exampleBusinessObject" />
|
|
<property name="targetMethod" value="doIt" />
|
|
</bean></programlisting>
|
|
|
|
<para>The above example will result in the <literal>doIt</literal>
|
|
method being called on the <literal>exampleBusinessObject</literal>
|
|
method (see below):</para>
|
|
|
|
<programlisting language="java">public class ExampleBusinessObject {
|
|
|
|
<lineannotation>// properties and collaborators</lineannotation>
|
|
|
|
public void doIt() {
|
|
<lineannotation>// do the actual work</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<programlisting language="xml">
|
|
<bean id="exampleBusinessObject" class="examples.ExampleBusinessObject"/></programlisting>
|
|
|
|
<para>Using the
|
|
<classname>MethodInvokingJobDetailFactoryBean</classname>, 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.</para>
|
|
|
|
<para>By default, Quartz Jobs are stateless, resulting in the
|
|
possibility of jobs interfering with each other. If you specify two
|
|
triggers for the same <classname>JobDetail</classname>, it might be
|
|
possible that before the first job has finished, the second one will
|
|
start. If <classname>JobDetail</classname> classes implement the
|
|
<interfacename>Stateful</interfacename> interface, this won't happen.
|
|
The second job will not start before the first one has finished. To make
|
|
jobs resulting from the
|
|
<classname>MethodInvokingJobDetailFactoryBean</classname>
|
|
non-concurrent, set the <literal>concurrent</literal> flag to
|
|
<literal>false</literal>.</para>
|
|
|
|
<programlisting language="xml">
|
|
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
|
|
<property name="targetObject" ref="exampleBusinessObject" />
|
|
<property name="targetMethod" value="doIt" />
|
|
<property name="concurrent" value="false" />
|
|
</bean></programlisting>
|
|
|
|
<note>
|
|
<para>By default, jobs will run in a concurrent fashion.</para>
|
|
</note>
|
|
</section>
|
|
|
|
<section id="scheduling-quartz-cron">
|
|
<title>Wiring up jobs using triggers and the
|
|
<classname>SchedulerFactoryBean</classname></title>
|
|
|
|
<para>We've created job details and jobs. We've also reviewed the
|
|
convenience bean that allows you to invoke a method on a specific
|
|
object. Of course, we still need to schedule the jobs themselves. This
|
|
is done using triggers and a
|
|
<classname>SchedulerFactoryBean</classname>. Several triggers are
|
|
available within Quartz. Spring offers two subclassed triggers with
|
|
convenient defaults: <classname>CronTriggerBean</classname> and
|
|
<classname>SimpleTriggerBean</classname>.</para>
|
|
|
|
<para>Triggers need to be scheduled. Spring offers a
|
|
<classname>SchedulerFactoryBean</classname> that exposes triggers to be
|
|
set as properties. <classname>SchedulerFactoryBean</classname> schedules
|
|
the actual jobs with those triggers.</para>
|
|
|
|
<para>Find below a couple of examples:</para>
|
|
|
|
<programlisting language="xml"><bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
|
|
<!-- see the example of method invoking job above -->
|
|
<property name="jobDetail" ref="jobDetail" />
|
|
<!-- 10 seconds -->
|
|
<property name="startDelay" value="10000" />
|
|
<!-- repeat every 50 seconds -->
|
|
<property name="repeatInterval" value="50000" />
|
|
</bean>
|
|
|
|
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
|
|
<property name="jobDetail" ref="exampleJob" />
|
|
<!-- run every morning at 6 AM -->
|
|
<property name="cronExpression" value="0 0 6 * * ?" />
|
|
</bean></programlisting>
|
|
|
|
<para>Now we've set up two triggers, one running every 50 seconds with a
|
|
starting delay of 10 seconds and one every morning at 6 AM. To finalize
|
|
everything, we need to set up the
|
|
<classname>SchedulerFactoryBean</classname>:</para>
|
|
|
|
<programlisting language="xml"><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
|
|
<property name="triggers">
|
|
<list>
|
|
<ref bean="cronTrigger" />
|
|
<ref bean="simpleTrigger" />
|
|
</list>
|
|
</property>
|
|
</bean></programlisting>
|
|
|
|
<para>More properties are available for the
|
|
<classname>SchedulerFactoryBean</classname> for you to set, such as the
|
|
calendars used by the job details, properties to customize Quartz with,
|
|
etc. Have a look at the <ulink
|
|
url="http://static.springframework.org/spring/docs/3.0.x/javadoc-api/org/springframework/scheduling/quartz/SchedulerFactoryBean.html">SchedulerFactoryBean
|
|
Javadoc</ulink> for more information.</para>
|
|
</section>
|
|
</section>
|
|
|
|
<section id="scheduling-jdk-timer">
|
|
<title>Using JDK Timer support</title>
|
|
|
|
<para>The other way to schedule jobs in Spring is to use JDK
|
|
<classname>Timer</classname> objects. You can create custom timers or use
|
|
the timer that invokes methods. Wiring timers is done using the
|
|
<classname>TimerFactoryBean</classname>.</para>
|
|
|
|
<section id="scheduling-jdk-timer-creating">
|
|
<title>Creating custom timers</title>
|
|
|
|
<para>Using the <classname>TimerTask</classname> you can create customer
|
|
timer tasks, similar to Quartz jobs:</para>
|
|
|
|
<programlisting language="java">public class CheckEmailAddresses extends TimerTask {
|
|
|
|
private List emailAddresses;
|
|
|
|
public void setEmailAddresses(List emailAddresses) {
|
|
this.emailAddresses = emailAddresses;
|
|
}
|
|
|
|
public void run() {
|
|
<lineannotation>// iterate over all email addresses and archive them</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Wiring it up is simple:</para>
|
|
|
|
<programlisting language="xml"><bean id="checkEmail" class="examples.CheckEmailAddress">
|
|
<property name="emailAddresses">
|
|
<list>
|
|
<value>test@springframework.org</value>
|
|
<value>foo@bar.com</value>
|
|
<value>john@doe.net</value>
|
|
</list>
|
|
</property>
|
|
</bean>
|
|
|
|
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask">
|
|
<lineannotation><!-- wait 10 seconds before starting repeated execution --></lineannotation>
|
|
<property name="delay" value="10000" />
|
|
<lineannotation><!-- run every 50 seconds --></lineannotation>
|
|
<property name="period" value="50000" />
|
|
<property name="timerTask" ref="checkEmail" />
|
|
</bean></programlisting>
|
|
|
|
<para><emphasis> Note that letting the task only run once can be done by
|
|
changing the <literal>period</literal> property to 0 (or a negative
|
|
value). </emphasis></para>
|
|
</section>
|
|
|
|
<section id="scheduling-jdk-timer-method-invoking-task">
|
|
<title>Using the
|
|
<classname>MethodInvokingTimerTaskFactoryBean</classname></title>
|
|
|
|
<para>Similar to the Quartz support, the <classname>Timer</classname>
|
|
support also features a component that allows you to periodically invoke
|
|
a method:</para>
|
|
|
|
<programlisting language="xml"><bean id="doIt" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
|
|
<property name="targetObject" ref="exampleBusinessObject" />
|
|
<property name="targetMethod" value="doIt" />
|
|
</bean></programlisting>
|
|
|
|
<para>The above example will result in the <literal>doIt</literal>
|
|
method being called on the <literal>exampleBusinessObject</literal> (see
|
|
below):</para>
|
|
|
|
<programlisting language="java">public class BusinessObject {
|
|
|
|
<lineannotation>// properties and collaborators</lineannotation>
|
|
|
|
public void doIt() {
|
|
<lineannotation>// do the actual work</lineannotation>
|
|
}
|
|
}</programlisting>
|
|
|
|
<para>Changing the <literal>timerTask</literal> reference of the
|
|
<classname>ScheduledTimerTask</classname> example to the bean
|
|
<literal>doIt</literal> will result in the <literal>doIt</literal>
|
|
method being executed on a fixed schedule.</para>
|
|
</section>
|
|
|
|
<section id="scheduling-jdk-timer-factory-bean">
|
|
<title>Wrapping up: setting up the tasks using the
|
|
<classname>TimerFactoryBean</classname></title>
|
|
|
|
<para>The <classname>TimerFactoryBean</classname> is similar to the
|
|
Quartz <classname>SchedulerFactoryBean</classname> in that it serves the
|
|
same purpose: setting up the actual scheduling. The
|
|
<classname>TimerFactoryBean</classname> sets up an actual
|
|
<classname>Timer</classname> and schedules the tasks it has references
|
|
to. You can specify whether or not daemon threads should be used.</para>
|
|
|
|
<programlisting language="xml"><bean id="timerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean">
|
|
<property name="scheduledTimerTasks">
|
|
<list>
|
|
<lineannotation><!-- see the example above --></lineannotation>
|
|
<ref bean="scheduledTask" />
|
|
</list>
|
|
</property>
|
|
</bean></programlisting>
|
|
</section>
|
|
</section>
|
|
</chapter> |