• 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实例一致。

  • 相关阅读:
    结构型设计模式——享元
    结构型设计模式——装饰模式
    结构型设计模式——外观
    结构型设计模式——桥接模式
    结构型设计模式——适配器模式(Go)
    创建型设计模式——工厂模式
    创建型设计模式——单例模式
    Linux03
    阅读《构建之法》八九十章
    作业五 5.2 5.3
  • 原文地址:https://www.cnblogs.com/jing-yi/p/13021905.html
Copyright © 2020-2023  润新知