Spring自动装配AOP循环依赖问题

52

我正在使用Java配置和@ComponentScan来初始化我的bean,以及@EnableAspectJAutoProxy(proxyTargetClass=true)使用cglib代理。

在这个项目中,我们有很多通过@Autowired相互关联的生成服务。它们运行得非常好。

但是,对于其中一些服务,我添加了@Async(我还在我的@Configuration类上添加了@EnableAsync(proxyTargetClass = true))。

之后,我遇到了以下问题:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'ConversationUserLocalService': Bean with name 'ConversationUserLocalService' has been injected into other beans [ConversationUserHistoryLocalService] i
n its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'a
llowEagerInit' flag turned off, for example.

我猜这是因为Spring在AOP创建代理之前使用@Async方法注入了服务,这可能是问题所在。问题应该如何解决?

为了尝试澄清我的问题,假设我有:

@Service A、B和C;

A已经自动装配了B和C,B已经自动装配了A和C,C已经自动装配了A和B;

C有一个标记为@Async的方法。

当Spring初始化applicationContext时,它尝试初始化A,但需要B和C,因此它会初始化它们。 但最终,AOP试图对C进行代理(因为@Async),然后它检测到自动装配到B和A中的C与C的代理不同,因此失败了。

我希望这可以更好地解释正在发生的事情。


请发布一个SSCCE - Bond - Java Bond
4个回答

51

最后,我使用@Lazy在服务上进行了排序(带有@Async注释的方法),并且在它们被自动连接时。 这样,我猜Spring只有在需要时才初始化和自动连接这些服务,而不是在应用程序上下文初始化时。


嘿,你能解释一下这部分吗:“它检测到自动装配的C进入B和A与C的代理不同”? - Sachin Sharma
2
当Spring创建代理以将异步行为添加到C中时,它不会更新A和B上的引用。因此,它们两个都引用了C的原始版本。 - Ignasi
1
谢谢你的解释。还有一个问题,这是否取决于Spring初始化服务的顺序。在你的例子中,如果Spring先初始化了C,那么同样的异常会发生吗? - Sachin Sharma
因此,将服务使用@Lazy @Autowired注入到其他服务中,使我获得了想要的结果。 - Philip

22

我遇到了同样的问题,并解决了这个问题:

  1. 我确定了哪个@Autowired属性是循环依赖的原因。

    例如:

    @Autowired
    private TestService testService;
    

    (识别应用程序崩溃原因的提示:尝试评论并查找哪个属性是原因)

  2. 一旦确定,只需在@Autowired变量顶部使用@Lazy

    例如:

  3. @Lazy
    @Autowired
    private TestService testService;
    

    应用程序运行顺畅。


12

-3

我通过在@Autowire注释前添加@Qualifier来解决类似的问题,例如:

@Autowired
@Qualifier("publisher")
private Publisher publisher;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接