Task Scheduling Simplifications in Spring 3.0 |
|

Continuing the Spring 3.0 "simplification series" started by Keith and Chris, I would like to provide a quick overview of simplifications in scheduling and task execution enabled by Spring 3.0.
I will be walking through a basic sample application that you can checkout from the spring-samples Subversion repository. It has been designed to be as simple as possible while showcasing both annotation-driven and XML-based approaches to scheduling tasks in Spring 3.0.
Let's begin with the annotation-driven approach. You can run it directly via the main() method in AnnotationDemo. If you take a look, you'll see that it's nothing more than a bootstrap for a Spring ApplicationContext:
public static void main(String[] args) {
new ClassPathXmlApplicationContext("config.xml", AnnotationDemo.class);
}
The reason nothing else is necessary is that the ApplicationContext contains an "active" component, which we will see in just a moment. Because of that component, the main() method will not exit. The config.xml is also minimal, containing only two elements:
<context:component-scan base-package="org/springframework/samples/task/basic/annotation"/> <task:annotation-driven/>
The "component-scan" element points to the package that contains our "beans". There are two of them: ScheduledProcessor and AsyncWorker. We'll look at those momentarily, but first take a look at the "annotation-driven" element. That's the one that is new in Spring 3.0, and it drives two annotations: @Scheduled and @Async. You could provide references to a Spring TaskScheduler and TaskExecutor with the "scheduler" and "executor" attributes respectively, but for this sample, we'll just rely on the defaults.
The ScheduledProcessor contains the @Scheduled annotation on a method and is therefore the "active" component I mentioned above. Since the 'annotation-driven' element exists in the configuration, this method will be registered with a Spring TaskScheduler instance that will execute the method periodically with a fixed delay of 30 seconds.
@Service
public class ScheduledProcessor implements Processor {
private final AtomicInteger counter = new AtomicInteger();
@Autowired
private Worker worker;
@Scheduled(fixedDelay = 30000)
public void process() {
System.out.println("processing next 10 at " + new Date());
for (int i = 0; i < 10; i++) {
worker.work(counter.incrementAndGet());
}
}
}
As you can see in the previous code excerpt, the Worker is invoked by the ScheduledProcessor within a loop. However, the AsyncWorker implementation contains the @Async annotation on its work(..) method, and due to the 'annotation-driven' element in the configuration, this will be wrapped in a proxy so that the method is actually invoked by a TaskExecutor instance. To verify that, the current thread name is displayed within that method. Likewise, to clarify that work is being performed concurrently, a sleep(..) call is made to simulate time-consuming work.
@Component
public class AsyncWorker implements Worker {
@Async
public void work(int i) {
String threadName = Thread.currentThread().getName();
System.out.println(" " + threadName + " beginning work on " + i);
try {
Thread.sleep(5000); // simulates work
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(" " + threadName + " completed work on " + i);
}
}
If you run the AnnotationDemo main() method, the output should look something like this:
processing next 10 at Mon Jan 04 18:20:52 EST 2010
SimpleAsyncTaskExecutor-1 beginning work on 1
SimpleAsyncTaskExecutor-2 beginning work on 2
SimpleAsyncTaskExecutor-3 beginning work on 3
SimpleAsyncTaskExecutor-5 beginning work on 5
SimpleAsyncTaskExecutor-4 beginning work on 4
SimpleAsyncTaskExecutor-6 beginning work on 6
SimpleAsyncTaskExecutor-7 beginning work on 7
SimpleAsyncTaskExecutor-8 beginning work on 8
SimpleAsyncTaskExecutor-9 beginning work on 9
SimpleAsyncTaskExecutor-10 beginning work on 10
SimpleAsyncTaskExecutor-1 completed work on 1
SimpleAsyncTaskExecutor-2 completed work on 2
SimpleAsyncTaskExecutor-3 completed work on 3
SimpleAsyncTaskExecutor-5 completed work on 5
SimpleAsyncTaskExecutor-6 completed work on 6
SimpleAsyncTaskExecutor-7 completed work on 7
SimpleAsyncTaskExecutor-8 completed work on 8
SimpleAsyncTaskExecutor-4 completed work on 4
SimpleAsyncTaskExecutor-10 completed work on 10
SimpleAsyncTaskExecutor-9 completed work on 9
There are a few things to notice about that output. First, the processing of 10 rows at a time will repeat every 30 seconds (due to @Scheduled). Second, the work items are being processed concurrently by different threads (due to @Async). There should be a pause of roughly 5 seconds between the last "beginning work" message and first "completed work" message. If the workers were all running in a single thread, we would instead see sequential beginning/completed pairs, and the entire process would take about 50 seconds. Of course, the temporal aspect cannot be captured here in the blog entry, so you really should download and run the sample yourself for the full effect (the project can be imported directly into SpringSource Tool Suite or another Eclipse-based environment with Maven support).
The last thing I want to show is the XML-based alternative for the @Scheduled annotation. The sample includes another class, SimpleProcessor, that does not contain @Scheduled on its process() method:
@Service
public class SimpleProcessor implements Processor {
private final AtomicInteger counter = new AtomicInteger();
public void process() {
System.out.println("processing next 10 at " + new Date());
for (int i = 0; i < 10; i++) {
System.out.println(" processing " + counter.incrementAndGet());
}
}
}
The XML is only slightly more verbose than the annotation-driven version, because Spring 3.0 now provides a "task" namespace to keep the configuration concise.
<context:component-scan base-package="org/springframework/samples/task/basic/xml"/>
<task:scheduled-tasks>
<task:scheduled ref="simpleProcessor" method="process" cron="3/10 * * * * ?"/>
</task:scheduled-tasks>
If you run the main() method in XmlDemo, you will see that process execute every 10 seconds. For variety, this one uses a cron expression instead of the simple fixed-delay. As a result, you will notice that the timing is based on a 3 second offset (:13, :23, etc), but of course cron expressions can be much more powerful than that (I just didn't want to create a sample that would only run on certain days or times of day). It's worth pointing out that the support for cron-based scheduling is included directly within Spring 3.0 itself.
Be sure to check out the Task Execution and Scheduling chapter of the Spring 3.0 Reference Manual to learn more about the new TaskScheduler abstraction and Trigger strategies that provide the foundation for what you've seen here. The reference manual also discusses additional elements provided by the "task" namespace for configuring TaskScheduler and TaskExecutor instances with specific thread pool settings.
I hope this post has provided a useful overview of these new features. Stay tuned to the SpringSource team blog for more Spring 3.0 related content.
Similar Posts
- Spring MVC 3.2 Preview: Making a Controller Method Asynchronous
- Spring Integration Samples
- Using Cloud Foundry Workers with Spring
- Spring Security 3.2 M1 Highlights, Servlet 3 API Support
- Request-Reply JMS with Spring 2.0





James Hoare says:
Added on January 5th, 2010 at 11:06 amThanks for the post Mark, but could you add an example for @Async and Futures? I'm trying to get an example working where my @Async method returns a future but I never get a value after calling Future.get()?
It would be great if you could provide an example for this.
Thanks
Peter Veentjer says:
Added on January 5th, 2010 at 11:09 amOr you can create a few lines of normal Java code using the ScheduledExecutor. Takes a lot less space and is much better understandable. The whole annotation thing is making code hard to understand.
ex-spring enthusiast.
Mark Fisher (blog author) says:
Added on January 5th, 2010 at 11:11 am@James I probably should have mentioned the support for Future return values, but I was trying to keep the post as short and simple as possible, hence the use of void-returning methods only.
When you have a Future return type, it should be quite straightforward. Maybe you can post your particular issue (with the get() call failing) in the Spring Forum and provide a link here?
You also might want to have a look at the AsyncResult implementation of Future that is provided in Spring 3.0. That makes it very easy to wrap your value.
Eko Kurniawan Khannedy says:
Added on January 5th, 2010 at 11:53 amyeah!!!
I Love Spring 3
John says:
Added on January 5th, 2010 at 12:09 pmWhat's the long term vision to enhance spring task scheduling? Could it be a replacement for Quartz?
Ron DiFrango says:
Added on January 5th, 2010 at 1:27 pmThis all looks great, but what about support for a clustered configuration where you only want one of the jobs in the cluster to fire?
Dave Syer (blog author) says:
Added on January 5th, 2010 at 2:01 pmA lot of use cases where we see people using Quartz are covered by the features provided by Spring Framework. For example, many people have used Quartz *only* for cron support, and not for clustering or persistent jobs, so "yes" to that part. For the sake of clarity: we do not plan to extend Spring Frameworks's role beyond scheduling/triggers, but there are other Spring projects with intersting features in this area. Spring Batch has persistence, so there is a class of use cases for which Spring Spring Batch is already a good alternative to Spring Quartz. Some of the more advanced features of Quartz (like cluster support) can be implemented using a combination of Spring and Spring Batch, but are not supported out of the box. Spring Batch Admin (which I blogged about a few weeks ago) fills in some of the blanks, and I expect in the future could be more interesting for more sophisticated users of Quartz.
Ron DiFrango says:
Added on January 5th, 2010 at 2:55 pmI would agree, that until my last client the Spring 3.0 implementation of Tasks would have been more than sufficient and saved me a ton of time. It would be nice to see it extended to support clustering via some sort of Quartz annotation or configuration mechanism so you get the best of both worlds.
Alberto Flores says:
Added on January 6th, 2010 at 9:51 amSimply awesome! – Thanks!
Isaac says:
Added on January 6th, 2010 at 10:47 pmMy main motivation for using Quartz in addition to the TaskExecutor is that when using Quartz, I have the ability to have my schedules 'filtered' by a Calendar, so that I can exclude blocks of time. I generally use Quartz Calendars in combination with CronTriggers to express something like "every hour on non-holidays during working hours". Would love a similar functionality independent of Quartz.
Atul says:
Added on January 7th, 2010 at 12:04 pmThere is no exceptional handling strategy defined for asynchronous method call.
when using @Async and return type is void,there is no clue in this framework to handle the exception.
In case method annotated with @Async returns future task,we can still call a get method on Futuretask and check if the thread is complete successsfully or throws concurrent exception.
any thoughts how to catch the exception when method using @Aysnc with returns type as void
Grzegorz Borkowski says:
Added on January 25th, 2010 at 11:41 amI've played with this new scheduling support. However, after switching to this new style, and using "task:scheduled-tasks" element in my application context file, I'm no longer able to shut down Tomcat on which application is deployed. I have to kill tomcat process. I guess this element creates some non-daemon thread which will stop VM from exiting.
Looks definitely like a bug.
Mark Fisher (blog author) says:
Added on January 25th, 2010 at 12:13 pm@Grzegorz there are non-daemon threads running within Spring's TaskScheduler. However, that implements Lifecycle and DisposableBean so the normal shutdown hook behavior should apply. Can you please post more information about your example in the forum? http://forum.springsource.org/
Thank you,
Mark
Grzegorz Borkowski says:
Added on January 25th, 2010 at 4:04 pmOk, I described it here: http://forum.springsource.org/showthread.php?p=280269#post280269
Krishna says:
Added on February 8th, 2010 at 4:15 pmCan Spring Integration 1.0.3 RELEASE run on Spring 3.0 ?
Thanks
James Heggs says:
Added on March 10th, 2010 at 10:38 amHi Mark,
I may have found a potential bug when using annotation based task scheduling and in particular:
@Scheduled(cron="* 10/1 * * * * ?")
After I have done a bit more testing if I find it is still an issue should I raise it on JIRA?
James Heggs says:
Added on March 10th, 2010 at 11:16 amPlease ignore my previous comment it looks like it was an issue with my setup.
Eliseo Soto says:
Added on April 2nd, 2010 at 4:49 pmOk, this might be a very basic question but what is the best way to externalize values like the fixedDelay here?:
@Scheduled(fixedDelay = 30000)
I'd like to be able to define/override that value with a properties file or command line argument without having to change the actual code.
Mark Fisher (blog author) says:
Added on April 2nd, 2010 at 5:08 pm@Eliseo With Spring 3.0.1 , you can externalize a cron expression like so: @Scheduled(cron = "${schedules.businessHours}")
However, there is no equivalent for 'fixedDelay' as of right now, because the annotation requires a long value for 'fixedDelay' whereas only a String value would accept the property placeholder since it is, by necessity, a String.
You could, of course, have a cron expression like so: "0/30 * * * * ?"
Or I guess you could do something like: "${seconds} * * * * ?"
Ben Gill says:
Added on April 13th, 2010 at 11:55 pm1 for cluster support
vikas says:
Added on April 28th, 2010 at 11:50 ami am getting the below error, while implementing annotation based scheduler in the spring MVC framework:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line 16 i
n XML document from ServletContext resource [/WEB-INF/config/myworld-config.xml]
is invalid; nested exception is org.xml.sax.SAXParseException: The prefix "task
" for element "task:annotation-driven" is not bound.
what i am missing? please help.
Mark Fisher (blog author) says:
Added on April 28th, 2010 at 12:11 pm@vikas You need to declare the namespace with an xmlns entry and a schemaLocation mapping. See the reference manual for some examples:
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/htmlsingle/spring-framework-reference.html#xsd-config-body
If you have any more questions, please post in the forum: http://forum.springsource.org/
-Mark
chiranjivi says:
Added on May 11th, 2010 at 1:55 amI have a return type File While using @Async annotation for my method with return type File i am trying to cast it to Future.From my method i am returning new AsyncResult type.But my spring configuration file will look like this.
while executing this i am getting this error
unsupported Message payload type
tzolov says:
Added on August 18th, 2010 at 2:49 amThe task:annotation-driven conflicts with the annotation driven JMX support. When i add @Async () to a JMX annotated class (e.g. @ManagedResource(..)) i get following startup exception:
MetadataMBeanInfoAssembler does not support JDK dynamic proxies – export the target beans directly or use CGLIB proxies instead
I guess the conflict is due to the interface-based AOP proxies used to instrument the @Async classes. According to the spring doc (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/jmx.html#jmx-context-mbeanexport):
"Do not use interface-based AOP proxies in combination with autodetection of JMX annotations in your bean classes. Interface-based proxies 'hide' the target class, which also hides the JMX managed resource annotations. Hence, use target-class proxies in that case: through setting the 'proxy-target-class' flag on , , etc. Otherwise, your JMX beans might be silently ignored at startup…"
Is there a known workaround for this?
Cheers,Chris
michał says:
Added on August 18th, 2010 at 9:33 amthis is b* that annotated scheduler is not destroyed on shutdown… there is not point of using it.
tzolov says:
Added on August 20th, 2010 at 10:26 amMichal, perhaps the scheduler-not-being-destroyed condition would contribute to the issue but the root cause seems to be an interference between to the aop proxies used in the task/scheduler and the @ManagedResources implementations. In result you may not able to use together Task and JMX annotation in the same class.
Anders Kristian Andersen says:
Added on December 4th, 2010 at 5:43 amIndeed this is easy
It took me some time to realize how easy it was, before I could actually use it.
It was because I was thinking about how to stop / resume the process etc.
Is there a way to get a "bean" handle to the control elements, so I can stop / resume – change schedule / crom properties and so on – on the fly?
Grzegorz Borkowski says:
Added on December 10th, 2010 at 8:40 amMark, I think you could update the last XML snippet of this article, so that task:scheduled-tasks element has scheduler="…" attribute. The Spring forum thread I mentioned above, suggested that lack of this attribute was the reason why Tomcat couldn't shut down properly (probably I had copied the snipped from this article to my app).
Dan Scrima says:
Added on January 25th, 2011 at 1:11 pmWe have an @Async method being called that queries a database, gets the entity, then calls a shell script that resides on the server which calls some ruby scripts, moves files, etc… The problem is that we keep getting "Cannot allocate memory" and the script doesn't run. Is there any issue with me using @Async on a method that needs to wait for a script to return using ProcessBuilder or something like that?
Thanks so much!
Cai Jiahua says:
Added on January 27th, 2011 at 4:34 amIf there is a lot of request invoking the async method,it will cause OutOfMemoryError.
How to control the thread number in the thread pool?Tks.
Mark Fisher (blog author) says:
Added on January 27th, 2011 at 9:06 am@Dan I'm not sure if it answers your question, but a method annotated with @Async can have a Future return type (instead of void). Then, even though its actual invocation is delegated to an Executor, the caller can wait for the result (often after doing some other task in the meantime).
Hope that helps.
-Mark
Mark Fisher (blog author) says:
Added on January 27th, 2011 at 9:09 am@Cai The examples above are relying on the default TaskExecutor and TaskScheduler instances. You can instead provide those explicitly using the 'task:executor' and 'task:scheduler' elements, respectively. In both cases, you can also add a 'pool-size' attribute.
-Mark
Cai Jiahua says:
Added on January 27th, 2011 at 10:04 amWhen the program invoke the @Async method, the springframework will create new thread or get the free thread from the pool?
The output above shows "SimpleAsyncTaskExecutor-1 beginning work on 1", SimpleAsyncTaskExecutor is the default TaskExecutor in @Async mode and can I config the other TaskExecutor?
Thank you.
Mark Fisher (blog author) says:
Added on January 27th, 2011 at 10:19 am@Cai,
Yes, you can use the 'task:executor' element, give it an 'id', and then reference that from the 'task:annotation-driven' element.
Does that answer your question?
Cai Jiahua says:
Added on January 28th, 2011 at 12:24 amI get it. Thank you for your help.
jk says:
Added on March 23rd, 2011 at 11:32 pm}
In the code:
@Async
@scheduled(cron="* 1/10 * * *")
myMethod(){}
Does this cause any problems..?? This seems to be working for me.
Marcio Tavares says:
Added on April 4th, 2011 at 12:40 pmHi Mark! Can I change some of these settings at runtime? I'm looking for some way of change threads pool size, queue capacity and so on, without restarting my app server, but I know that may not be possible. Do you know if I can, at least, change the rate of scheduler's pooling at runtime? I'm using fixed-rate timing for scheduled methods. Thanks in advance!
Dave Syer (blog author) says:
Added on April 4th, 2011 at 12:50 pmYou can expose the TaskExecutor (e.g. as an MBean or through a custom service in your app), and that allows changes at runtime, but there are some restrictions. Oddly enough, changing the polling schedule is part a demo I'm working on for JAX London next week. Come and see it if you get a chance, and I'll post the slides and source code somewhere anyway. There is some trickery involved, and it will only work for cron schedules (which should be fine as long as you don't need subsecond polling frequency).
Marcio Tavares says:
Added on April 4th, 2011 at 7:26 pmHi Dave, thanks for your answer! I did some tests and noticed I can expose TaskExecutor (via ThreadPoolTaskExecutor) and change its parameters as I wish, but on the other hand, I was unable to expose 'task:scheduled-tasks' object, which is the one that have the objects with the 'fixed-rate' value I need to change. Here is my configuration (very similar to the one in the article):
I checked the source code and noticed that ScheduledExecutorTask class has the attributes fixedRate, delay, period etc but I believe this class represents only one scheduled task, among all others to be scheduled, and it's not the right place to do that change (BTW, I was unable to inject it anywhere).
I was looking for something else and found an article, here in the "pings and trackbacks", called "Custom Scheduling in Spring", where the author says it's not possible to change the timing rate at runtime. Well, if this is true, I will unfortunatelly have to continue this way, no problem, but it would be nice if in the future this feature was implemented (or with some time available, I could handle that
).
Last but not least, thanks for your invitation to attend JAX London but I'm afraid I couldn't do it as I'm a few miles away from there (I'm from Rio de Janeiro) although it would be very interesting to be there! Best wishes!
Marcio Tavares says:
Added on April 4th, 2011 at 7:30 pmSorry… I tried to post some raw XML code… here's the "entitized" one:
<task:scheduled-tasks scheduler="scheduler">
<task:scheduled ref="processor" method="process" fixed-rate="10000" />
</task:scheduled-tasks>
(erase it if you want)
Dave Syer (blog author) says:
Added on April 5th, 2011 at 3:41 amThe author of your pingback is clearly wrong, since I am going to show everyone how to do it next week (and if that was an invitation to come to Rio to present my solution, I accept, but we'll have to schedule it later). I also raised an issue https://jira.springsource.org/browse/SPR-8205 that will make it easier to do once the new feature is added.
Saravanakumar says:
Added on May 5th, 2011 at 1:47 amGetting the below exception while trying with @Async with the below code. Appreciate any help.
package springservice;
import java.util.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.scheduling.annotation.*;
import org.springframework.context.support.*;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.*;
@Service
public class SpringScheduler {
@Autowired
private Worker worker;
@Scheduled(fixedDelay=10000)
public void run()
{
System.out.println(" run called ");
worker.work();
}
public static void main(String a[])
{
new ClassPathXmlApplicationContext("spring.xml");
}
}
interface WorkerInterface
{
public void work();
}
@Component
class Worker implements WorkerInterface
{
@Async
public void work()
{
System.out.println(new Date() "::" Thread.currentThread().getName());
}
}
[/java] Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springScheduler': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private springservice.Worker springservice.SpringScheduler.worker; nested exception is java.lang.IllegalArgumentException: Can not set springservice.Worker field springservice.SpringScheduler.worker to springservice.$Proxy11 [java]at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
[/java] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1074) [java]at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:517)
[/java] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) [java]at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
[/java] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) [java]at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
[/java] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190) [java]at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:580)
[/java] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895) [java]at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
[/java] at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:139) [java]at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:83)
[/java] at springservice.SpringScheduler.main(SpringScheduler.java:24) [java]Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private springservice.Worker springservice.SpringScheduler.worker; nested exception is java.lang.IllegalArgumentException: Can not set springservice.Worker field springservice.SpringScheduler.worker to springservice.$Proxy11
[/java] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:502) [java]at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:84)
[/java] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:282) [java]… 13 more
[/java] Caused by: java.lang.IllegalArgumentException: Can not set springservice.Worker field springservice.SpringScheduler.worker to springservice.$Proxy11 [java]at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
[/java] at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150) [java]at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
[/java] at java.lang.reflect.Field.set(Field.java:657) [java]at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:498)
[/java] ... 15 more [java]Java Result: 1
BUILD SUCCESSFUL
Total time: 1 second
Mark Fisher (blog author) says:
Added on May 5th, 2011 at 8:17 amThe field that you are trying to inject needs to be the interface type (WorkerInterface) rather than the concrete type (Worker) since the async version is a proxy. The proxy implements the WorkerInterface but is not assignable to the concrete Worker type.
Saravanakumar says:
Added on May 5th, 2011 at 11:21 amYes, thats done the trick.
Pawel Kolodziej says:
Added on May 6th, 2011 at 5:04 pmGreat. Just what I was looking for. Spring rocks.
Zoltan says:
Added on June 1st, 2011 at 7:29 amMark,
Great post!
One question: Could you explain why AtomicInteger is needed in the ScheduledProcessor?
As I see it a simple int would also be ok because the process method is executed in a single thread.
Arun.R.U says:
Added on June 5th, 2011 at 8:28 amHello!!!
How to set the generic timezone for scheduler ?
Thanks…
Cai Jiahua says:
Added on June 10th, 2011 at 4:05 amI have a question.
If I use @Async, How to config to create the daemon thread ?
Mark Fisher (blog author) says:
Added on June 10th, 2011 at 5:54 am@Zoltan: the AtomicInteger is not strictly necessary in the code shown, but if the "processor" were expected to be invoked concurrently, it would be necessary. In this particular case, it's the code inside the work() method of the "worker" that really needs to be capable of handling concurrent invocations.
Mark Fisher (blog author) says:
Added on June 10th, 2011 at 5:56 am@Cai: when defining the 'annotation-driven' element within the task namespace, an 'executor' reference may be provided. That can be any instance of Executor configured however you need it to be. This section of the reference manual discusses the various implementations and configuration options provided by Spring: http://static.springsource.org/spring/docs/3.0.5.RELEASE/spring-framework-reference/htmlsingle/spring-framework-reference.html#scheduling-task-executor
Diego says:
Added on June 22nd, 2011 at 5:02 pmHi, i'm trying to implement a Scheduled method but each 10 seg this run two times. See the log and the code:
My code:
// each 10 sec
@Scheduled(fixedDelay = 10000)
public void syncronizeTransactions() {
try {
String threadName = Thread.currentThread().getName();
System.out.println( "Executando " threadName " em " (new Date()).toString());
} catch (Exception e) {
e.printStackTrace();
}
}
My output console:
Executando pool-1-thread-1 em Wed Jun 22 18:52:39 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:52:40 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:52:50 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:52:51 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:00 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:01 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:10 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:11 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:21 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:22 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:31 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:32 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:41 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:42 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:53:52 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:53:53 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:54:02 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:54:03 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:54:12 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:54:13 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:54:23 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:54:24 BRT 2011
Executando pool-1-thread-1 em Wed Jun 22 18:54:33 BRT 2011
Executando pool-2-thread-1 em Wed Jun 22 18:54:34 BRT 2011
Look that each 10 seconds the method execute two times. Why?
My config:
I,m using Spring framework version 3.0.5
Dave Syer (blog author) says:
Added on June 23rd, 2011 at 12:24 am@Diego: I think your configuration got swallowed by the CMS. Last time I saw a similar problem it turned out there were two beans from the same class, e.g. in 2 different application contexts. Make sure you aren't doing something like defining a bean in XML and using a component scan.
Diego says:
Added on June 24th, 2011 at 2:11 pmThanks Dave. The problem is solved using your orientation. I was defined two contexts loading beans…
RahulSharna says:
Added on July 13th, 2011 at 3:59 am@Mark, truly a Great writeup.
@Dave, Is there a way by which we can incorporate these @Async features to replace AsyncItemProcessor & AsyncItemWriter as a part of Spring Batch Integration
Dave Syer (blog author) says:
Added on July 13th, 2011 at 4:49 am@Rahul: I guess you could use @Async in an item processor POJO (wrapped in ItemProcessorAdapter), or an a regular ItemProcessor. You would still need to collect the results, so AsyncItemWriter would be useful for that. I'm not sure it buys you much to use @Async, other than the centralization of the TaskExecutor configuration.
Nitish says:
Added on September 12th, 2011 at 6:24 amHi All,
In the above given example By – Mark Fisher. there is a main() method. In java web application using ecplise and spring as framework how is it possible to execute a class with main() method. plsss sum1 help me on this…..m really in bad need of this example.
Andreas Höhmann says:
Added on September 12th, 2011 at 7:33 amHow can I run async Tasks with autowired dependencies?
Example:
class worker {
@Autowired
Foobar importantForWork;
@Async void doit() {
importantForWork.calculate();
}
}
This will not work if "Foobar importantForWork" is session scoped … why?
I think the new thread doesnt have the correct request attributes to resolve the
right bean from the session scoped proxy.
Any ideas?
Mark Fisher (blog author) says:
Added on September 12th, 2011 at 8:03 am@Nitish The purpose of that main() method is nothing more than a bootstrap (it creates the ApplicationContext from the config.xml). In a webapp, you don't even need that, because you can rely on Spring's ContextLoaderListener instead. See this section of the Spring reference manual for more detail:http://static.springsource.org/spring/docs/3.0.6.RELEASE/spring-framework-reference/htmlsingle/spring-framework-reference.html#context-create
Hope that helps,
Mark
Mark Fisher (blog author) says:
Added on September 12th, 2011 at 8:29 am@Andreas You are correct. The task scheduler itself is really a "background" process. It sounds like what you want would need to be driven by a Session listener that schedules a task upon Session-creation and cancels that task upon Session-destruction/timeout.
Andrew Swan says:
Added on September 28th, 2011 at 10:55 pm@vikas, the namespace is http://www.springframework.org/schema/task and its location is http://www.springframework.org/schema/task/spring-task-3.0.xsd
Rajive says:
Added on October 18th, 2011 at 7:05 amgreat job
Bing says:
Added on October 18th, 2011 at 10:32 amGreat Job. Could you please give some clue for how to download the whole project from subversion? I tried eclipse subclipse and TortoiseSVN, and got error. Thanks.
hareendran says:
Added on February 26th, 2012 at 1:50 pmi had implemented the task scheduler
i hit upon a strange this code was not working if I use default-lazy-init=true. I use the component scan for loading the beans. once i remove the lazy-init= true it works like dizzy.
even more stranger if i go ahead with using @schdeuled rather than the XML with default-init then also process was running. should I raise A JIRA for this?
dchucks says:
Added on April 9th, 2012 at 1:54 amExcellent notes! My requirement is that a User should be able to schedule new jobs through a Web GUI. All the examples I saw so far related to Spring Batch with Quartz or Spring Task Scheduler refer to having "static" or Pre-configured jobs in the XML or in Java code, which means that adding new jobs would need a re-deployment of the web-application. Can't we schedule jobs on the fly and make them persistent to survive a server restart?
Mark Fisher (blog author) says:
Added on April 9th, 2012 at 8:04 am@dchucks If you use the 'trigger' attribute instead of 'cron' or 'fixed-rate'/'fixed-delay' then you can reference any bean that implements the Trigger strategy interface. That interface has one method: nextExecutionTime(TriggerContext). There you can have any logic you need, such as reading the "next time" from a DB or some other dynamic backing store.
Hope that helps.
-Mark