Skip to content

Backport "Enable Executor qualification with @Async" [SPR-9443] #14079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue May 25, 2012 · 6 comments
Closed
Labels
in: core Issues in core modules (aop, beans, core, context, expression)
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented May 25, 2012

Chris Beams opened SPR-9443 and commented


This issue is a backport sub-task of #11513

Issue Links:

3 votes, 3 watchers

@spring-projects-issues
Copy link
Collaborator Author

Chris Beams commented

commit 896aed6dcaebd98cd01a48e7ef11abd829265d41
Author: Chris Beams <[email protected]>
Commit: Chris Beams <[email protected]>

    Refactor and deprecate TransactionAspectUtils
    
    TransactionAspectUtils contains a number of methods useful in
    retrieving a bean by type+qualifier. These methods are functionally
    general-purpose save for the hard coding of PlatformTransactionManager
    class literals throughout.
    
    This commit generifies these methods and moves them into
    BeanFactoryUtils primarily in anticipation of their use by async method
    execution interceptors and aspects when performing lookups for qualified
    executor beans e.g. via @Async(qualifier).
    
    The public API of TransactionAspectUtils remains backward compatible;
    all methods within have been deprecated, and all calls to those methods
    throughout the framework refactored to use the new BeanFactoryUtils
    variants instead.
    
    Issue: SPR-9443
    Backport-Issue: SPR-6847
    Backport-Commit: 096693c46fba6e09b346a498b7002abd4d6540a9
commit b9aef0a8cda807b031cb0e993ab1e131daa0c90a
Author: Chris Beams <[email protected]>
Commit: Chris Beams <[email protected]>

    Polish async method execution infrastructure
    
    In anticipation of substantive changes required to implement @Async
    executor qualification, the following updates have been made to the
    components and infrastructure supporting @Async functionality:
    
     - Fix trailing whitespace and indentation errors
     - Fix generics warnings
     - Add Javadoc where missing, update to use {@code} tags, etc.
     - Avoid NPE in AopUtils#canApply
     - Organize imports to follow conventions
     - Remove System.out.println statements from tests
     - Correct various punctuation and grammar problems
    
    Issue: SPR-9443
    Backport-Issue: SPR-6847
    Backport-Commit: 3fb11870d9e9fc47651c08442ac7e85140788579
commit e7ef443d651d5e0899ea8e60d8bec0a7f7c40b2f
Author: Chris Beams <[email protected]>
Commit: Chris Beams <[email protected]>

    Support executor qualification with @Async#value
    
    Prior to this change, Spring's @Async annotation support was tied to a
    single AsyncTaskExecutor bean, meaning that all methods marked with
    @Async were forced to use the same executor. This is an undesirable
    limitation, given that certain methods may have different priorities,
    etc. This leads to the need to (optionally) qualify which executor
    should handle each method.
    
    This is similar to the way that Spring's @Transactional annotation was
    originally tied to a single PlatformTransactionManager, but in Spring
    3.0 was enhanced to allow for a qualifier via the #value attribute, e.g.
    
      @Transactional(ptm1)
      public void m() { ... }
    
    where ptm1 is either the name of a PlatformTransactionManager bean or
    a qualifier value associated with a PlatformTransactionManager bean,
    e.g. via the <qualifier> element in XML or the @Qualifier annotation.
    
    This commit introduces the same approach to @Async and its relationship
    to underlying executor beans. As always, the following syntax remains
    supported
    
      @Async
      public void m() { ... }
    
    indicating that calls to #m will be delegated to the default executor,
    i.e. the executor provided to
    
      <task:annotation-driven executor=.../>
    
    or the executor specified when authoring a @Configuration class that
    implements AsyncConfigurer and its #getAsyncExecutor method.
    
    However, it now also possible to qualify which executor should be used
    on a method-by-method basis, e.g.
    
      @Async(e1)
      public void m() { ... }
    
    indicating that calls to #m will be delegated to the executor bean
    named or otherwise qualified as e1. Unlike the default executor
    which is specified up front at configuration time as described above,
    the e1 executor bean is looked up within the container on the first
    execution of #m and then cached in association with that method for the
    lifetime of the container.
    
    Class-level use of Async#value behaves as expected, indicating that all
    methods within the annotated class should be executed with the named
    executor. In the case of both method- and class-level annotations, any
    method-level #value overrides any class level #value.
    
    This commit introduces the following major changes:
    
     - Add @Async#value attribute for executor qualification
    
     - Introduce AsyncExecutionAspectSupport as a common base class for
       both MethodInterceptor- and AspectJ-based async aspects. This base
       class provides common structure for specifying the default executor
       (#setExecutor) as well as logic for determining (and caching) which
       executor should execute a given method (#determineAsyncExecutor) and
       an abstract method to allow subclasses to provide specific strategies
       for executor qualification (#getExecutorQualifier).
    
     - Introduce AnnotationAsyncExecutionInterceptor as a specialization of
       the existing AsyncExecutionInterceptor to allow for introspection of
       the @Async annotation and its #value attribute for a given method.
       Note that this new subclass was necessary for packaging reasons -
       the original AsyncExecutionInterceptor lives in
       org.springframework.aop and therefore does not have visibility to
       the @Async annotation in org.springframework.scheduling.annotation.
       This new subclass replaces usage of AsyncExecutionInterceptor
       throughout the framework, though the latter remains usable and
       undeprecated for compatibility with any existing third-party
       extensions.
    
     - Add documentation to spring-task-3.2.xsd and reference manual
       explaining @Async executor qualification
    
     - Add tests covering all new functionality
    
    Note that the public API of all affected components remains backward-
    compatible.
    
    Issue: SPR-9443
    Backport-Issue: SPR-6847
    Backport-Commit: ed0576c1811bbb3a17e2e9aed2810dc3c9097a09
commit 7612be5dd3bcd9326f9a821af111e4c92e550bca
Author: Chris Beams <[email protected]>
Commit: Chris Beams <[email protected]>

    Test meta-@Async executor qualification
    
    Prove that Async#value is respected even when using @Async as a meta
    annotation.
    
    Issue: SPR-9443
    Backport-Issue: SPR-6847
    Backport-Commit: 37e024c6ebfdc57874e5024b3e9efa69de05fa44
commit 04e700a067058901149be913ecebbcb707498d6b
Author: Chris Beams <[email protected]>
Commit: Chris Beams <[email protected]>

    Introduce BeanFactoryAnnotationUtils
    
    Commit 3f387eb9cf710e8e902861e74f7d6c5981a0b5ea refactored and
    deprecated TransactionAspectUtils, moving its #qualifiedBeanOfType
    and related methods into BeanFactoryUtils. This created a package cycle
    between beans.factory and beans.factory.annotation due to use of the
    beans.factory.annotation.Qualifier annotation in these methods.
    
    This commit breaks the package cycle by introducing
    beans.factory.annotation.BeanFactoryAnnotationUtils and moving these
    @Qualifier-related methods to it. It is intentionally similar in name
    and style to the familiar BeanFactoryUtils class for purposes of
    discoverability.
    
    There are no backward-compatibilty concerns associated with this change
    as the cycle was introduced, caught and now fixed before a release.
    
    Issue: SPR-9443
    Backport-Issue: SPR-6847
    Backport-Commit: a4b00c732b13aa1628161cb35d49463c5c39d38c

@spring-projects-issues
Copy link
Collaborator Author

Ken Young commented

Having problems when testing this option.

I have my task executor configured as follows:


<task:executor id="threadPoolTaskExecutor" pool-size="2-10" queue-capacity="20" />

	<task:annotation-driven executor="threadPoolTaskExecutor" />

<task:executor id="otherTaskExecutor" pool-size="2-10" queue-capacity="20" />

And my method is annotated as follows:

@Async(value="otherTaskExecutor")
public Future<String> findBalanceAsync(final String account) {

Instead of attaching to "otherTaskExecutor", it grabs "threadPoolTaskExecutor" instead.

@spring-projects-issues
Copy link
Collaborator Author

Chris Beams commented

Hi Ken,

Could you possibly put together a reproduction project? Thanks.

@spring-projects-issues
Copy link
Collaborator Author

Ken Young commented

Sure---Where to I put it. Attach to the ticket?

@spring-projects-issues
Copy link
Collaborator Author

Chris Beams commented

Attaching to the issue is acceptable, but following the instructions here is preferred: https://github.com/SpringSource/spring-framework-issues#readme.

@spring-projects-issues
Copy link
Collaborator Author

Ken Young commented

I created https://jira.springsource.org/browse/SPR-9575 to follow up on this. Working on the example project

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression)
Projects
None yet
Development

No branches or pull requests

1 participant