Annotation Support for Scheduling and Asynchronous Execution
Spring provides annotation support for both task scheduling and asynchronous method execution.
Enable Scheduling Annotations
To enable support for @Scheduled
and @Async
annotations, you can add @EnableScheduling
and
@EnableAsync
to one of your @Configuration
classes, as the following example shows:
@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}
You can pick and choose the relevant annotations for your application. For example,
if you need only support for @Scheduled
, you can omit @EnableAsync
. For more
fine-grained control, you can additionally implement the SchedulingConfigurer
interface, the AsyncConfigurer
interface, or both. See the
SchedulingConfigurer
and AsyncConfigurer
javadoc for full details.
If you prefer XML configuration, you can use the <task:annotation-driven>
element,
as the following example shows:
<task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
<task:executor id="myExecutor" pool-size="5"/>
<task:scheduler id="myScheduler" pool-size="10"/>
Note that, with the preceding XML, 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
.
The default advice mode for processing @Async annotations is proxy which allows
for interception of calls through the proxy only. Local calls within the same class
cannot get intercepted that way. For a more advanced mode of interception, consider
switching to aspectj mode in combination with compile-time or load-time weaving.
|
The @Scheduled
annotation
You can add the @Scheduled
annotation to a method, along with trigger metadata. For
example, the following method is invoked every five seconds with a fixed delay,
meaning that the period is measured from the completion time of each preceding
invocation:
@Scheduled(fixedDelay=5000)
public void doSomething() {
// something that should execute periodically
}
If you need a fixed-rate execution, you can change the property name specified within the annotation. The following method is invoked every five seconds (measured between the successive start times of each invocation):
@Scheduled(fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
For fixed-delay and fixed-rate tasks, you can specify an initial delay by indicating the
number of milliseconds to wait before the first execution of the method, as the following
fixedRate
example shows:
@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
If simple periodic scheduling is not expressive enough, you can provide a cron expression. For example, the following executes only on weekdays:
@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
// something that should execute on weekdays only
}
You can also use the zone attribute to specify the time zone in which the cron
expression is resolved.
|
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, those would typically have been provided through dependency injection.
As of Spring Framework 4.3, Make sure that you are not initializing multiple instances of the same |
The @Async
annotation
You can provide the @Async
annotation on a method so that invocation of that method
occurs asynchronously. In other words, the caller returns immediately upon
invocation, while the actual execution of the method occurs in a task that has been
submitted to a Spring TaskExecutor
. In the simplest case, you can apply the annotation
to a method that returns void
, as the following example shows:
@Async
void doSomething() {
// this will be executed asynchronously
}
Unlike the methods annotated with the @Scheduled
annotation, these methods can expect
arguments, because they are invoked in the “normal” way by callers at runtime rather
than from a scheduled task being managed by the container. For example, the following code is
a legitimate application of the @Async
annotation:
@Async
void doSomething(String s) {
// this will be executed asynchronously
}
Even methods that return a value can be invoked asynchronously. However, such methods
are required to have a Future
-typed return value. This still provides the benefit of
asynchronous execution so that the caller can perform other tasks prior to calling
get()
on that Future
. The following example shows how to use @Async
on a method
that returns a value:
@Async
Future<String> returnSomething(int i) {
// this will be executed asynchronously
}
@Async methods may not only declare a regular java.util.concurrent.Future return type
but also Spring’s org.springframework.util.concurrent.ListenableFuture or, as of Spring
4.2, JDK 8’s java.util.concurrent.CompletableFuture , for richer interaction with the
asynchronous task and for immediate composition with further processing steps.
|
You can not use @Async
in conjunction with lifecycle callbacks such as
@PostConstruct
. To asynchronously initialize Spring beans, you currently have to use
a separate initializing Spring bean that then invokes the @Async
annotated method on the
target, as the following example shows:
public class SampleBeanImpl implements SampleBean {
@Async
void doSomething() {
// ...
}
}
public class SampleBeanInitializer {
private final SampleBean bean;
public SampleBeanInitializer(SampleBean bean) {
this.bean = bean;
}
@PostConstruct
public void initialize() {
bean.doSomething();
}
}
There is no direct XML equivalent for @Async , since such methods should be designed
for asynchronous execution in the first place, not externally re-declared to be asynchronous.
However, you can manually set up Spring’s AsyncExecutionInterceptor with Spring AOP,
in combination with a custom pointcut.
|
Executor Qualification with @Async
By default, when specifying @Async
on a method, the executor that is used is the
one configured when enabling async support,
i.e. the “annotation-driven” element if you are using XML or your AsyncConfigurer
implementation, if any. However, you can use the value
attribute of the @Async
annotation when you need to indicate that an executor other than the default should be
used when executing a given method. The following example shows how to do so:
@Async("otherExecutor")
void doSomething(String s) {
// this will be executed asynchronously by "otherExecutor"
}
In this case, "otherExecutor"
can be the name of any Executor
bean in the Spring
container, or it may be the name of a qualifier associated with any Executor
(for example, as
specified with the <qualifier>
element or Spring’s @Qualifier
annotation).
Exception Management with @Async
When an @Async
method has a Future
-typed return value, it is easy to manage
an exception that was thrown during the method execution, as this exception is
thrown when calling get
on the Future
result. With a void
return type,
however, the exception is uncaught and cannot be transmitted. You can provide an
AsyncUncaughtExceptionHandler
to handle such exceptions. The following example shows
how to do so:
public class MyAsyncUncaughtExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
// handle exception
}
}
By default, the exception is merely logged. You can define a custom AsyncUncaughtExceptionHandler
by using AsyncConfigurer
or the <task:annotation-driven/>
XML element.