Spring循环依赖
Spring循环依赖
- 问题及日志
- 问题代码截图
- 解决方案
- 使用@Lazy延迟加载
- 重构代码结构
- 本次问题解决
- 相关问题及解释
- 参考资料
问题及日志
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 exceptionorg.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@Autowiredprivate ChangeLogRepository changeLogRepository;
}
不建议使用该方案,因为发生循环依赖本质是代码设计不合理,
要从根本上解决问题,重构代码。
重构代码结构
注意不适用本次出现的问题
-
检查是否可以将部分依赖关系改为构造函数注入
import org.springframework.beans.factory.annotation.Autowired;public class AttachmentLogInterceptor implements Interceptor {private final ChangeLogRepository changeLogRepository;// 构造函数注入@Autowired // 如果只有一个构造函数,可以省略这个注解public AttachmentLogInterceptor(ChangeLogRepository changeLogRepository) {this.changeLogRepository = changeLogRepository;}// 其他方法保持不变... }
-
考虑将某些通用功能抽离到独立的工具类中
-
检查BaseServiceImpl的mapper注入方式
本次问题解决
根据代码分析,DataChangeAdvice 通过构造函数直接依赖 SqlSessionTemplate 和 MapperHelper,
而 SqlSessionTemplate 的创建依赖 MyBatis 自动配置(MybatisAutoConfiguration),最终形成以下循环链:DataChangeAdvice → SqlSessionTemplate → MybatisAutoConfiguration → (其他拦截器/组件) → DataChangeAdvice
修改代码:延迟依赖初始化(核心思路)
@Aspect
@Component
@Slf4j
public class DataChangeAdvice {// 关键点:使用 ObjectProvider 延迟获取 SqlSessionTemplateprivate final ObjectProvider<SqlSessionTemplate> sqlSessionTemplateProvider;private final ObjectProvider<MapperHelper> mapperHelperProvider;// 构造函数改造:不再直接依赖 SqlSessionTemplatepublic 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.csdn.net/qq_27759825/article/details/129027330