Since Spring 3.2 it should be possible to use a qualifier in the “Async” annotation of a method, to indicate which specific executor to use. For example, I have the following class, that is supposed to collect the HTML from a website asynchronously:
HTMLFetcher Interface
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.concurrent.Future;
import org.springframework.scheduling.annotation.Async;
public interface HTMLFetcher {
Future<HTMLFetcher.HTMLFetcherResult> getHTML(String baseUrl,Date date);
interface HTMLFetcherResult {
String getHTMLResult();
Date getDate();
}
}
TestHTMLFetcher Class
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Date;
import java.util.concurrent.Future;
import org.apache.log4j.Logger;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import agonesgr.html.HTMLFetcher;
@Component
public class TestHTMLFetcher implements HTMLFetcher{
@Async(value="htmlFetcherExecutor")
public Future<HTMLFetcher.HTMLFetcherResult> getHTML(String baseUrl, Date date) {
try {
System.out.println("Before execute!!");
Thread.sleep(100000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
HTMLFetcher.HTMLFetcherResult r = new TestHTMLFetcher.HTMLFetcherResultImpl("",new Date());
return new AsyncResult<HTMLFetcherResult>(r);
}
private static class HTMLFetcherResultImpl implements HTMLFetcherResult{
private String htmlResult;
private Date date;
public HTMLFetcherResultImpl(String htmlResult, Date date) {
super();
this.htmlResult = htmlResult;
this.date = date;
}
public String getHTMLResult() {
return htmlResult;
}
public Date getDate() {
return date;
}
}
}
And the following excerpt from the context.xml file:
This didn’t work! I submitted 10 tasks to the executor and 10 thread, instead of 1 as I had instructed it had been created. I digged into the Spring code a bit and found the AnnotationAsyncExecutionInterceptor class that was doing tbe job of assigning tasks from methods annotated as async to executors. Putting a breakpoint on its getExecutorQualifier method it became evident why it doesn’t work.
You need to annotate the interface method rather than the class with the:
@Async(value="htmlFetcherExecutor")
annotation. In my example that is the getHTML method of the HTMLFetcher interface. It now works. I am not sure if it was done on purpose (i.e. if it’s part of the specification). I don’t have time to read the related documentation or search the Spring Jira. However, I would assume that the right place to put the annotation is the implementation. I may want to have two implementations of the same method, one decorated with “Async” that will be asynchronously executed and another without any annotation that will be synchronously executed.