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.