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是否已经被创建过。
个人理解:
二级缓存: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实例一致。