Scheduling and asynchronous execution with Spring

You want to execute cron jobs or call your methods asynchronously? Thanks to Spring’s annotation support for scheduling and asynchronous execution you can achieve this in a few minutes.

Some xml magic

At first define your task executor and scheduler. The following lines will create an instance of ThreadPoolTaskExecutor and an instance of ThreadPoolTaskScheduler with the given pool sizes. The task element annotation-driven allows you to use Spring’s annotations for scheduling and asynchronous execution within the beans defined in your application context.

<bean id="myClass" class="my.project.path.myClass" />
<task:annotation-driven executor="myExecutor" scheduler="myScheduler" />
<task:executor id="myExecutor" pool-size="5" />
<task:scheduler id="myScheduler" pool-size="10" />

The @Scheduled annotation

With the @Scheduled annotation you can execute your method as a cron job. Using this annotation requires that the method to be scheduled must be of type void and must not expect any arguments. The following examples show you how to use the @Scheduled annotation.
If you want periodic scheduling you can use the property fixedRate. In this example the method would be executed every 42 seconds.

@Scheduled(fixedRate = 42000)
public void execute() {
    // do something
}

If you prefer cron expressions you can use them either. The following example is analogue to the example above only using cron expressions. The annotated method would be executed each full minute and every 7 seconds.

@Scheduled(cron = "*/7 * * * * *")
public void execute() {
    // do something
}

Without question you have much more possibilities with cron expressions than with periodic scheduling. In this example your method would be executed every weekday (Monday to Friday) on 9.45 am.

@Scheduled(cron = "0 45 9 * * MON-FRI")
public void execute() {
    // do something
}

A pretty cool feature is that you even can use placeholders for your cron expression which are resolved against the configured property-placeholder.

@Scheduled(cron = "${myclass.cron.execute.sth}")
public void execute() {
    // do something
}

Define where the properties are loaded from within your application context:

<context:property-placeholder location="classpath:application.properties"/>

Then the properties are loaded from the file which contains your cron-expressions like this:

myclass.cron.execute.sth=0 45 9 * * MON-FRI

The @Async annotation

The @Async annotation allows you to invoke your method asynchronously. The execution of the method will occur in a task that has been submitted to the TaskExecutor defined in your application context. Contrary to the methods annotated with the @Scheduled annotations the methods you annotate with @Async may be of other type than void and can expect arguments.
This is a simple example of a @Async annotated method without a return value.

@Async
void execute(String string) {
    // do something asynchronously
}

Like mentioned above your @Async annotated method may have a return value. However this return value must be of type Future. This means that first the other tasks are performed and then is called get() on that Future.

@Async
Future<String> execute(String string) {
    // do something asynchronously
}

Further information

Have a look at the Spring Framework Reference Documentation

Kommentare

  1. fixedDelayString="${delay.in.milliseconds.in.string}"

  2. So what is role of "pool-size" parameter

  3. @Manu Gupta: Could you give me any further information on that?

  4. Hi,
    I have used the @Scheduled & @Service annotation and also configured my application context file....
    My server is also starting without any errors, yet my annotated method is not running
    Can you please guide.
    Thanks

  5. Ok, I found a solution for my own problem:
    Use the "trigger" property to reference a bean that implements the Trigger interface and then I can specify any placeholder name that I want:
    <bean id="dtcCronTrigger" class="org.springframework.scheduling.support.CronTrigger" >
    <constructor-arg name="cronExpression" value="${dtc.cron.expression}" />
    </bean>
    <task:scheduled-tasks scheduler="dtcScheduler">
    <!-- <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dataTransferCoordinator.cron.execute.sth}"/>-->
    <task:scheduled ref="dataTransferCoordinator" method="run" trigger="dtcCronTrigger"/>
    </task:scheduled-tasks>

  6. Ok, one my try, the last post was misleading, here is what it meant to say:
    I’m using XML config for my Spring application context and the following didn’t work:
    <task:scheduled-tasks scheduler="dtcScheduler">
    <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dtc.cron.expression}"/>
    </task:scheduled-tasks>
    but after reading your post I found that the following did work:
    <task:scheduled-tasks scheduler="dtcScheduler">
    <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dataTransferCoordinator.cron.execute.sth}"/>
    </task:scheduled-tasks>

  7. The XML snippets were excluded from my last post so I've included them in this one:
    I’m using XML config for my Spring application context and the following didn’t work:
    <task:scheduled-tasks scheduler="dtcScheduler">
    <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dataTransferCoordinator.cron.execute.sth}"/>
    </task:scheduled-tasks>
    but after reading your post I found that the following did work:
    <task:scheduled-tasks scheduler="dtcScheduler">
    <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dtc.cron.expression}"/>
    </task:scheduled-tasks>
    <task:scheduled-tasks scheduler="dtcScheduler">
    <task:scheduled ref="dataTransferCoordinator" method="run" cron="${dataTransferCoordinator.cron.execute.sth}"/>
    </task:scheduled-tasks>

  8. Thanks for this post, it has been helpful. How did you determine that "myClass.cron.execute.sth" is the correct name for the cron expression placeholder? I have been trying to find the right name for this property for my own class because I'm using Spring Context's Property Placeholder/Override mechanism and it expects the placeholder to be of the form "beanName.property". I'm using XML config for my Spring application context and the following didn't work:
    but after reading your post I found that the following did work:

  9. Hello Lalit,
    To be honest I'm not sure if you can annotate the same method with both, @Scheduled and @Async. Anyway I would prefer to use two separate methods, since the both annotations have different characteristics.
    e.g. a method to be scheduled via the @Scheduled annotation must be of type void and must not expect any arguments, whereas a @Async method may expect arguments and even have a return value.
    I think the best way is to have a scheduled method that triggers an asynchronous method. How scheduled and asynchronous services/methods may work hand in hand you can look up here:
    http://blog.springsource.org/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
    (see the code excerpts of ScheduledProcessor and AsyncWorker)
    Hope this helps!

  10. Hi Aljona,
    Great help !!!
    Can you please tell me how could I use @Async and @Scheduled both on a method. I want to perform some task asynchronously on daily basis.
    Thanks,
    Lalit

  11. Unfortunately the properties fixedDelay and fixedRate expect a long value, so you can use placeholders only for the property cron.
    However if you want to avoid setting the fixedDelay value in your Java class, you can set it in your application context.
    You define like described above ("Some xml magic") your scheduler and executor and add this:
    <code>
    <task:scheduled-tasks scheduler="myScheduler">
    <task:scheduled ref="myClass" method="myMethod" fixed-delay="2000" />
    </task:scheduled-tasks>
    </code>
    Hope this helps! :-)

  12. Hi thanks for the post.
    I have a question. Do you know if i can use fixedDelay with a placeholders?
    @Scheduled(fixedDelay = ${myclass.cron.execute.sth})
    Thanks for the advise.