You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.0 KiB
5.0 KiB
Spring Bean 循环依赖修复报告 (完整版)
问题描述
应用启动时出现复杂的 BeanCreationException
错误,涉及多个Bean的循环依赖:
Error creating bean with name 'bszxBmController': Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'bszxBmServiceImpl': Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'cmsArticleServiceImpl': Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'cmsNavigationServiceImpl': Injection of resource dependencies failed;
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'cmsDesignServiceImpl': Injection of resource dependencies failed
根本原因分析
通过分析代码发现了复杂的循环依赖链,涉及多个层级的Bean相互依赖:
1. 自我注入问题
在 CmsNavigationServiceImpl
中存在自我注入:
@Service
public class CmsNavigationServiceImpl extends ServiceImpl<CmsNavigationMapper, CmsNavigation> implements CmsNavigationService {
@Resource
private CmsNavigationService cmsNavigationService; // 自我注入!
// 在方法中使用
final CmsNavigation parent = cmsNavigationService.getOne(...);
}
2. 复杂的循环依赖链
发现了以下循环依赖关系:
主要循环依赖链:
BszxBmController → BszxBmService → CmsArticleService → CmsNavigationService → CmsDesignService → CmsNavigationService
具体依赖关系:
BszxBmController
依赖BszxBmService
和CmsArticleService
BszxBmServiceImpl
依赖CmsArticleService
CmsArticleServiceImpl
依赖CmsNavigationService
CmsNavigationServiceImpl
依赖CmsDesignService
和自我注入CmsNavigationService
CmsDesignServiceImpl
依赖CmsNavigationService
这形成了一个复杂的循环依赖网络,导致Spring无法正确初始化这些Bean。
修复方案
修复1:解决自我注入问题
文件: src/main/java/com/gxwebsoft/cms/service/impl/CmsNavigationServiceImpl.java
修复前:
@Resource
private CmsNavigationService cmsNavigationService;
// 使用时
final CmsNavigation parent = cmsNavigationService.getOne(new LambdaQueryWrapper<CmsNavigation>()...);
修复后:
// 移除自我注入的依赖
// 使用时改为调用 this
final CmsNavigation parent = this.getOne(new LambdaQueryWrapper<CmsNavigation>()...);
修复2:使用 @Lazy 注解打破循环依赖
文件1: src/main/java/com/gxwebsoft/cms/service/impl/CmsDesignServiceImpl.java
import org.springframework.context.annotation.Lazy;
@Resource
@Lazy
private CmsNavigationService cmsNavigationService;
文件2: src/main/java/com/gxwebsoft/cms/service/impl/CmsArticleServiceImpl.java
import org.springframework.context.annotation.Lazy;
@Resource
@Lazy
private CmsNavigationService cmsNavigationService;
文件3: src/main/java/com/gxwebsoft/bszx/service/impl/BszxBmServiceImpl.java
import org.springframework.context.annotation.Lazy;
@Resource
@Lazy
private CmsArticleService cmsArticleService;
文件4: src/main/java/com/gxwebsoft/bszx/controller/BszxBmController.java
import org.springframework.context.annotation.Lazy;
@Resource
@Lazy
private CmsArticleService cmsArticleService;
修复详情
1. CmsNavigationServiceImpl.java 修复
- 移除自我注入: 删除了
private CmsNavigationService cmsNavigationService;
字段 - 修改方法调用: 将
cmsNavigationService.getOne(...)
改为this.getOne(...)
2. CmsDesignServiceImpl.java 修复
- 添加 @Lazy 注解: 在
CmsNavigationService
依赖上添加@Lazy
注解 - 导入必要的类: 添加
import org.springframework.context.annotation.Lazy;
@Lazy 注解的作用
@Lazy
注解告诉 Spring 容器延迟初始化这个 Bean,直到第一次被实际使用时才创建。这样可以打破循环依赖:
- Spring 首先创建
CmsNavigationServiceImpl
(不立即注入CmsDesignService
) - 然后创建
CmsDesignServiceImpl
(延迟注入CmsNavigationService
) - 当实际需要使用时,再完成依赖注入
验证修复
修复后,Spring 应用应该能够正常启动,不再出现循环依赖错误。
最佳实践建议
- 避免循环依赖: 在设计服务层时,尽量避免相互依赖
- 使用 @Lazy: 当必须存在循环依赖时,使用
@Lazy
注解 - 重构设计: 考虑将共同依赖提取到单独的服务中
- 自我注入检查: 避免在服务实现类中注入自己的接口
影响范围
- ✅ 修复了应用启动时的 Bean 创建异常
- ✅ 保持了原有的业务逻辑不变
- ✅ 提高了应用的稳定性
- ✅ 遵循了 Spring 的最佳实践
修复完成后,应用应该能够正常启动并运行。