Skip to content

Problem in @Async annotation and circular dependencies #35554

@Rustieo

Description

@Rustieo

Hi developers,

When class A and class B have a circular dependency, and A is annotated with @Async (meaning A will be processed by AsyncAnnotationBeanPostProcessor and wrapped in a proxy)

@Service
public class A {
    @Autowired
    private B b;
    @Async
    public void test () {
        System.out.println("async");
    }
}
@Service
@DependsOn("a")
public class B {
    @Autowired
    private A a;

}

then the following exception occurs:

Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] in its raw version as part of a circular reference, ......

From the source code of doCreateBean, I found that this happens because exposedObject != bean.

Image

Here above, exposedObject refers to the proxy object, while bean refers to the original object. The reason exposedObject becomes the proxy object is that even though AsyncAnnotationBeanPostProcessor.postProcessAfterInitialization checks whether the bean has already been proxied(the following picture), the proxy object itself stays in the cache, so neither exposedObject nor bean point to it. As a result, exposedObject is not an implementation of Advised and finally returns a new proxy object, which makes exposedObject != bean, and thus the exception is thrown.

Image

In older versions of Spring, I found that the root cause was that AsyncAnnotationBeanPostProcessor did not implement SmartInstantiationAwareBeanPostProcessor. Therefore, AsyncAnnotationBeanPostProcessor did not participate in getEarlyBeanReference, which later caused postProcessAfterInitialization to return a new proxy object.

In the current versions, AsyncAnnotationBeanPostProcessor has already been changed to implement SmartInstantiationAwareBeanPostProcessor. However, it does not override the getEarlyBeanReference method, which means the issue still exists.

So my question is:
Why doesn’t AsyncAnnotationBeanPostProcessor override getEarlyBeanReference to wrap it instead of returning the bean itself

This answer was translated with AI, so there might be some inaccuracies. Thank you for your clarification!!!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    in: coreIssues in core modules (aop, beans, core, context, expression)status: waiting-for-triageAn issue we've not yet triaged or decided on

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions