spring循环依赖

参考文章:

三级缓存解决循环依赖问题:https://juejin.im/post/5e9b26fe6fb9a03c7413841e

1、spring IOC容器各类结构

 获取bean和创建bean流程:

入口:AbstractBeanFactory的getBean( ),-->doGetBean( )。

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
    protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

        //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖
        //如果指定的是别名,将别名转换为规范的Bean名称
        final String beanName = transformedBeanName(name);
        Object bean;

        // Eagerly check singleton cache for manually registered singletons.
        //先尝试从一级缓存中取是否已经有被创建过的单态类型的Bean
        //对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建
        Object sharedInstance = getSingleton(beanName);

  先通过getSingleton(beanName)尝试从一级缓存中获取bean对象,这里会调父类DefaultSingletonBeanRegistry中的方法,三级缓存也是在该父类中定义:

  /** Cache of singleton objects: bean name --> bean instance */  //一级缓存
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

    /** Cache of singleton factories: bean name --> ObjectFactory */  //三级缓存
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

    /** Cache of early singleton objects: bean name --> bean instance */  //二级缓存
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

在AbstractBeanFactory中有一个Set<String>  alreadyCreated,记录beanName对应的Bean是否已经被创建过。

个人理解:

一级缓存:singletonObjects 存储已经创建完成(初始化和属性注入)的bean

二级缓存:earlySingletonObjects,存储提前暴露的bean(只实例化还未属性注入)

  作用:这是spring大量使用缓存提高性能的提现,如果每次都是通过三级缓存的工厂去获取对象,逻辑很复杂(如遍历后置处理器,判断是否要创建代理对象等),使用二级缓存可以提高bean创建流程。

三级缓存:singletonFactoris,维护着bean的ObjectFactory

获取bean:

通过getSingleton(beanName)获取bean时,先从一级缓存取,没有的话从二级缓存取,再没有的话如果允许循环依赖则从三级缓存取,取出singletonFactory,通过singletonFactory.getObject()获取bean,将从三级缓存得到的bean存入二级缓存,并清除三级缓存。

 

何时放入三级缓存:

在实例化bean后,spring会将实例化后的bean提前暴露,即在实例化后注入属性前,将bean对应的ObjectFactory(此处理解为bean对应的工厂类)放入三级缓存中。

 

示例:

(1)AService实例化后,在注入属性前提前曝光,将其加入三级缓存singletonFactories中,供其他bean使用;

(2)AService通过populateBean注入BService,从缓存中获取BService,发现缓存中没有,开始创建BService实例;

(3)BService实例也会在属性注入前提前曝光,加入三级缓存中,此时三级缓存中有AService和BService;

(4)BService在进行属性注入时,发现有AService引用,此时,创建AService时,会先从缓存中获取AService(先从一级缓存中取,没有取到后,从二级缓存中取,也没有取到,这时,从三级缓存中取出),这时会清除三级缓存中的AService,将其将其加入二级缓存earlySingletonObjects中,并返回给BService供其使用;

(5)BService在完成属性注入,进行初始化,这时会加入一级缓存,这时会清除三级缓存中的BService,此时,三级缓存为空,二级缓存中有AService,一级缓存中有BService;

(6)BService初始化后注入AService中,AService进行初始化,然后通过getSingleton方法获取二级缓存,赋值给exposedObject,最后将其加入一级缓存,清除二级缓存AService;

 

注:因为BService中注入的是二级缓存中的bean,在AService注入完成后,会将最终的bean和二级缓存中提前暴露的bean指向同一个对象,保证BService中注入的AService实例一致。

原文地址:https://www.cnblogs.com/jing-yi/p/13021905.html