springboot 数据源依赖于mapper 导致循环引用报错

介绍情况

springboot项目,mybatis-plus 持久层框架

DynimcDatasource 依赖于 Mapper
Mapper 依赖于  SqlSessionFoctory
SqlSessionFactory 依赖于 DynimcDatasource

循环依赖报错 The dependencies of some of the beans in the application context form a cycle:

DynimcDatasource -> Mapper -> SqlSessionFoctory -> DynimcDatasource

bean生成方式

@Component
public class DynimcDatasource{
    @Resource
    private Mapper mapper;

    @PostConstruct
    public void init() {
        mapp.list();
        ...
    }
  ...
}

@Mapper
public interface Mapper extends BaseMapper<XXX>{
}

@Configuration
public class xxxConfig{

  @Bean(name = "sqlSessionFactory")
  public SqlSessionFactory sqlSessionFactory(DynamicDataSource 
    dynamicDataSource)
            throws Exception {
        MybatisSqlSessionFactoryBean bean = new 
        MybatisSqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setTransactionFactory(new 
        MultiDataSourceTransactionFactory());
        return bean.getObject();     
   }
        
}

奇怪的一个地方:

我在其他地方注入DynimcDatasource,和 Mapper之后,spring就能处理循环依赖了,

注入方式如下

@Configuration
public class xxxConfig{
  @Resource
  private DynimcDatasource dynimcDatasource;
  
  @Resource
  private Mapper mapper;
}
求解释原因。
并求问是否有更好的接触方案,感觉这么弄有点丑。

解决:循环引用的一个节点上注入对象时加@Lazy可以解决循环引用问题

@Configuration
public class xxxConfig{

  @Bean(name = "sqlSessionFactory")
  public SqlSessionFactory sqlSessionFactory(@Lazy DynamicDataSource 
    dynamicDataSource)
            throws Exception {
        MybatisSqlSessionFactoryBean bean = new 
        MybatisSqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setTransactionFactory(new 
        MultiDataSourceTransactionFactory());
        return bean.getObject();     
   }
        
}
保留的疑问:在不使用@Lazy时,为什么我在其他对象中注入了DynimcDatasource 和 Mapper 之后,spring就是解决循环依赖了呢
阅读 5.9k
3 个回答
✓ 已被采纳新手上路,请多包涵

我最终的解决方案是这样的:生成sqlSessionFactory注入DynamicDataSource的时候用@Lazy懒加载。然后执行顺序就是,先创建sqlSessionFactory,最后创建DynamicDataDsource

@Configuration
public class xxxConfig{

  @Bean(name = "sqlSessionFactory")
  public SqlSessionFactory sqlSessionFactory(@Lazy DynamicDataSource 
    dynamicDataSource)
            throws Exception {
        MybatisSqlSessionFactoryBean bean = new 
        MybatisSqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setTransactionFactory(new 
        MultiDataSourceTransactionFactory());
        return bean.getObject();     
   }
        
}

反思:@Lazy是工程上的可行方案。 但实际底层的原因确实是依赖设计有问题。
我这边后来整理了逻辑,实际上是两个数据源,把这两个数据源的逻辑分开后就没有依赖问题了。 
* 原本是ormA+B -> 数据源A+B -> ormA+B。
* 整理后逻辑为 ormA-> 数据源A-> ormB -> 数据源B.

orm框架依赖数据源,数据源的优先级较高,然后你数据源里面又依赖orm框架的类,这不是无限套娃嘛!设计就有问题,先问问自己为什么要这么设计,如果只是为了初始化一部分数据,容器提供了一大堆扩展点

spring 是解决了循环依赖的问题的,除非你使用的是构造器注入的方式,才会出现循环依赖的报错。如果使用的是setter,字段注入的方式,并且bean是单例,spring 提供循环依赖的问题解决。我去测试了下,确实是可以解决。你可以关注下注入的方式。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题