小程序开发-服务端
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

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 依赖 BszxBmServiceCmsArticleService
  • 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,直到第一次被实际使用时才创建。这样可以打破循环依赖:

  1. Spring 首先创建 CmsNavigationServiceImpl(不立即注入 CmsDesignService
  2. 然后创建 CmsDesignServiceImpl(延迟注入 CmsNavigationService
  3. 当实际需要使用时,再完成依赖注入

验证修复

修复后,Spring 应用应该能够正常启动,不再出现循环依赖错误。

最佳实践建议

  1. 避免循环依赖: 在设计服务层时,尽量避免相互依赖
  2. 使用 @Lazy: 当必须存在循环依赖时,使用 @Lazy 注解
  3. 重构设计: 考虑将共同依赖提取到单独的服务中
  4. 自我注入检查: 避免在服务实现类中注入自己的接口

影响范围

  • 修复了应用启动时的 Bean 创建异常
  • 保持了原有的业务逻辑不变
  • 提高了应用的稳定性
  • 遵循了 Spring 的最佳实践

修复完成后,应用应该能够正常启动并运行。