You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
933 lines
42 KiB
933 lines
42 KiB
<?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> |