在软件开发中,依赖是不可避免的。我们经常需要在应用程序的不同组件之间建立依赖关系,以实现功能的模块化和复用。然而,有时候依赖关系可能变得复杂,甚至导致循环依赖的问题。在本文中,我们将通过项目中实际遇到的异常探讨一些解决循环依赖问题的技巧,帮助你在开发过程中优雅地处理依赖关系。
异常详情
Spring Bean配置中存在循环依赖的问题。具体而言,名为'mngAuditWorkbenchSummaryRepositoryImpl'的Bean已经注入到其他多个Bean中,但Spring无法解决这个循环引用。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'myCardService': Unsatisfied dependency expressed through field 'workRepository'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mngAuditRepositoryImpl': Bean with name 'mngAuditRepositoryImpl' has been injected into other beans [zwInfoServiceImpll] in 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 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:593)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda{
mathJaxContainer[0]}0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:897)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:879)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:551)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:405)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
at cn.xj.CMCCApplication.main(CMCCApplication.java:31)
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'mngAuditRepositoryImpl': Bean with name 'mngAuditRepositoryImpl' has been injected into other beans [zwInfoServiceImpl] in 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 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:623)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:516)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda{
mathJaxContainer[1]}0(AbstractBeanFactory.java:324)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:322)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1307)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1227)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640)
异常说明
错误信息表明在你的Spring Bean配置中存在循环依赖的问题。具体而言,名为'mngAuditWorkbenchSummaryRepositoryImpl'的Bean已经注入到其他多个Bean中,但Spring无法解决这个循环引用。
循环依赖发生在两个或多个Bean直接或间接地相互依赖,创建了一个无法由Spring解决的循环。
解决方案
分析依赖关系:确定涉及循环引用的Bean,并确定它们之间的依赖关系。了解依赖关系图有助于找到解决方案。
打破循环依赖:有几种方法可以打破循环依赖。以下是一些常见的方法:
- 构造函数注入:考虑使用构造函数注入而不是字段或setter注入。这样可以在对象创建时解决依赖关系。
- 使用@Autowired的setter注入:使用setter注入和@Autowired注解,同时在setter方法上添加@Autowired注解。然后,通过setter方法设置必要的依赖项,而不是字段注入。
- 使用基于接口的代理:如果可能,为涉及的Bean引入接口,并使用基于接口的代理来解决循环依赖。
重新审查设计:循环依赖通常是设计问题的指示。请考虑审查应用程序的架构,并查看是否有机会进行重构或解耦相关的Bean。
使用延迟初始化:你可以尝试对循环引用中的一个或多个Bean使用延迟初始化。可以通过使用@Lazy注解来配置这些Bean。
使用getBeanNamesForType:不要使用自动装配,而是使用getBeanNamesForType方法,并将allowEagerInit标志设置为false。这可以帮助你识别涉及循环引用的Bean,并手动解决依赖关系。
我们在实际项目中使用的使用延迟初始化 的方法,代码如下:
@Service
@Lazy
public class workRepository {
//业务代码
}
总结
解决循环依赖问题需要细心分析依赖关系,并采取适当的措施来解决问题。选择合适的方法取决于具体的情况和使用的技术栈。在实施任何更改之前,确保进行充分的测试