spring-projects / spring-projects/spring-framework
Problem in `@Async` annotation and circular dependencies
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
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.
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.
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!!!!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the circular A/B dependency from the issue, then trace bean creation through doCreateBean and AsyncAnnotationBeanPostProcessor. Read SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference alongside postProcessAfterInitialization to compare the early and final references. Done means determining whether the exception is expected and documenting or testing the supported behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100