Spring循环依赖

问题及日志

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2025-05-21 09:05:55.193 DEBUG 1 --- [           main] o.h.c.a.Slf4jFailureAnalysisReporter     : Application failed to start due to an exception

org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration': Requested bean is currently in creation: Is there an unresolvable circular reference?

中间日志省略

2025-05-21 09:05:55.194 ERROR 1 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

The dependencies of some of the beans in the application context form a cycle:

   dataChangeAdvice defined in URL [jar:file:/inja-demand.jar!/BOOT-INF/classes!/com/inja/demand/record/aspect/DataChangeAdvice.class]
┌─────┐
|  org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
↑     ↓
|  attachmentLogInterceptor (field private com.inja.demand.record.domain.repository.ChangeLogRepository com.inja.demand.requirement.interceptor.AttachmentLogInterceptor.changeLogRepository)
↑     ↓
|  changeLogRepositoryImpl (field private io.choerodon.mybatis.common.BaseMapper io.choerodon.mybatis.service.BaseServiceImpl.mapper)
↑     ↓
|  changeLogMapper defined in URL [jar:file:/inja-demand.jar!/BOOT-INF/classes!/com/inja/demand/record/infra/mapper/ChangeLogMapper.class]
└─────┘

问题代码截图

在这里插入图片描述
在这里插入图片描述

解决方案

使用@Lazy延迟加载

在其中一个依赖项上添加@Lazy注解来打破循环,例如在AttachmentLogInterceptor的字段注入处:

public class AttachmentLogInterceptor {
    @Lazy
    @Autowired
    private ChangeLogRepository changeLogRepository;
}

不建议使用该方案,因为发生循环依赖本质是代码设计不合理,
要从根本上解决问题,重构代码。

重构代码结构

注意不适用本次出现的问题

  1. 检查是否可以将部分依赖关系改为构造函数注入

    import org.springframework.beans.factory.annotation.Autowired;
    
    public class AttachmentLogInterceptor implements Interceptor {
    
        private final ChangeLogRepository changeLogRepository;
    
        // 构造函数注入
        @Autowired // 如果只有一个构造函数,可以省略这个注解
        public AttachmentLogInterceptor(ChangeLogRepository changeLogRepository) {
            this.changeLogRepository = changeLogRepository;
        }
    
        // 其他方法保持不变...
    }
    
  2. 考虑将某些通用功能抽离到独立的工具类中

  3. 检查BaseServiceImpl的mapper注入方式

本次问题解决

根据代码分析,DataChangeAdvice 通过构造函数直接依赖 SqlSessionTemplate 和 MapperHelper,
而 SqlSessionTemplate 的创建依赖 MyBatis 自动配置(MybatisAutoConfiguration),最终形成以下循环链:

DataChangeAdvice → SqlSessionTemplate → MybatisAutoConfiguration → (其他拦截器/组件) → DataChangeAdvice

修改代码:延迟依赖初始化(核心思路)

@Aspect
@Component
@Slf4j
public class DataChangeAdvice {
    // 关键点:使用 ObjectProvider 延迟获取 SqlSessionTemplate
    private final ObjectProvider<SqlSessionTemplate> sqlSessionTemplateProvider;
    private final ObjectProvider<MapperHelper> mapperHelperProvider;

    // 构造函数改造:不再直接依赖 SqlSessionTemplate
    public DataChangeAdvice(
        ObjectProvider<SqlSessionTemplate> sqlSessionTemplateProvider,
        ObjectProvider<MapperHelper> mapperHelperProvider
    ) {
        this.sqlSessionTemplateProvider = sqlSessionTemplateProvider;
        this.mapperHelperProvider = mapperHelperProvider;
    }

    // 实际使用时再获取依赖(例如在切面方法中)
    @Around("@annotation(yourAnnotation)")
    public Object handleDataChange(ProceedingJoinPoint joinPoint) throws Throwable {
        SqlSessionTemplate sqlSession = sqlSessionTemplateProvider.getObject();  // 按需获取
        MapperHelper helper = mapperHelperProvider.getIfAvailable();
        // 业务逻辑...
        return joinPoint.proceed();
    }
}

相关问题及解释

在这里插入图片描述

参考资料

https://blog.youkuaiyun.com/qq_27759825/article/details/129027330

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值