Spring循环依赖原理&三级缓存源码详解(原创)
❤️💛🧡💚💔🖤💜💙❤💕💞💓💗❣️💝💘💖❤️💛🧡💚💔🖤💜💙❤💕💞💓💗❣️💝💘💖💖💖 💖
❤️作者简介:2022新星计划第三季云原生与云计算赛道Top5🏅、华为云享专家🏅、云原生领域潜力新星🏅 💖
💛博客首页:C站个人主页🌞 💖
❤️💛🧡💚💔🖤💜💙❤💕💞💓💗❣️💝💘💖❤️💛🧡💚💔🖤💜💙❤💕💞💓💗❣️💝💘💖💖💖 💖
文章目录
-
- Spring循环依赖原理&三级缓存源码详解
-
- 几种循环依赖及其区别
-
- 第一种:单例setter注入循环依赖(spring可解决)
- 第二种:构造器注入循环依赖(无法解决)
- 第三种:多例/原型setter注入循环依赖(无法解决)
- 三级缓存源码详解
-
- DefaultSingletonBeanRegistry
-
- DefaultSingletonBeanRegistry定义的核心变量
- registerSingleton注册单例bean底层源码
- addSingleton添加单例bean底层源码
- addSingletonFactory添加单例工厂源码
-
- 为什么这段代码仅仅是移除二级缓存数据?
- getSingleton(String beanName, boolean allowEarlyReference)底层源码
- 深入Spring源码解析三级缓存(单例工厂)什么时候提前添加bean对象
-
- AbstractAutowireCapableBeanFactory类
-
- doCreateBean部分核心方法
Spring循环依赖原理&三级缓存源码详解
几种循环依赖及其区别
第一种:单例setter注入循环依赖(spring可解决)
- 这种情况spring可以通过三级缓存去解决
@Componentpublic class AService { @Autowired private BService bService; public BService getbService() { return bService; } public void setbService(BService bService) { this.bService = bService; } @Override public String toString() { return "AService{" + "bService=" + bService + '}'; }}
@Componentpublic class BService { @Autowired private AService aService; public AService getaService() { return aService; } public void setaService(AService aService) { this.aService = aService; }}
- 测试:
AService aService = (AService) applicationContext.getBean("AService");System.out.println(aService);
AService{bService=com.boot.csdn.bean.BService@2eed37f4}
第二种:构造器注入循环依赖(无法解决)
@Componentpublic class AService { private BService bService; AService(BService bService){ this.bService=bService; } @Override public String toString() { return "AService{" + "bService=" + bService + '}'; }}
@Componentpublic class BService { private AService aService; BService(AService aService){ this.aService=aService; }}
AService aService = (AService) applicationContext.getBean("AService");System.out.println(aService);
- 测试:
***************************APPLICATION FAILED TO START***************************Description:The dependencies of some of the beans in the application context form a cycle:┌─────┐| AService defined in file [D:\vue\CsdnVisitor\target\classes\com\boot\csdn\bean\AService.class]↑ ↓| BService defined in file [D:\vue\CsdnVisitor\target\classes\com\boot\csdn\bean\BService.class]└─────┘Process finished with exit code 1
第三种:多例/原型setter注入循环依赖(无法解决)
@Component@Scope("prototype") //多例beanpublic class AService { @Autowired private BService bService; public void setbService(BService bService) { this.bService = bService; } public BService getbService() { return bService; } @Override public String toString() { return "AService{" + "bService=" + bService + '}'; }}
@Component@Scope("prototype")//多例beanpublic class BService { @Autowired private AService aService; public void setaService(AService aService) { this.aService = aService; } public AService getaService() { return aService; }}
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'AService': Requested bean is currently in creation: Is there an unresolvable circular reference?
三级缓存源码详解
DefaultSingletonBeanRegistry
DefaultSingletonBeanRegistry定义的核心变量
/** Cache of singleton objects: bean name to bean instance. */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of early singleton objects: bean name to bean instance. */private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);/** Cache of singleton factories: bean name to ObjectFactory. */private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Set of registered singletons, containing the bean names in registration order. */private final Set<String> registeredSingletons = new LinkedHashSet<>(256);/** Names of beans that are currently in creation. */private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));/** Collection of suppressed Exceptions, available for associating related causes. */@Nullableprivate Set<Exception> suppressedExceptions;
- singletonObjects:单例池(一级缓存),key=beanName,value=bean对象
- 存放的bean对象都是经过了完整的bean的生命周期。(比如依赖注入)
- earlySingletonObjects:提前曝光的单例bean池(二级缓存),key=beanName,value=bean对象
- 存放的bean对象没有经过完整的bean的生命周期,也就是没有进行依赖注入、初始化前、初始化、初始化等阶段。
- singletonFactories:用来打破循环依赖最重要的一个缓存,单例bean工厂(三级缓存),key=beanName,value=对象工厂
registerSingleton注册单例bean底层源码
@Overridepublic void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {Assert.notNull(beanName, "Bean name must not be null");Assert.notNull(singletonObject, "Singleton object must not be null");synchronized (this.singletonObjects) {Object oldObject = this.singletonObjects.get(beanName);if (oldObject != null) {throw new IllegalStateException("Could not register object [" + singletonObject +"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");}addSingleton(beanName, singletonObject);}}
- 首先判断beanName和singletonObject是否为空,如果为空就抛出IllegalArgumentException异常;
- 然后用synchronized锁住当前的singletonObjects对象,通过beanName去找到单例池对应的对象(oldObject),如果不为空(说明该bean已经存在单例池中)则报错。
- 如果为空,说明该bean对象还没有存在于单例池中,说明可以把该对象添加进单例池,此时就会调用下面的addSingleton(beanName, singletonObject)方法去添加。
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
- 同样,我们是把对象添加进单例池,所以为了线程安全我们要先锁住singletonObjects对象;
- 调用this.singletonObjects.put(beanName, singletonObject)方法把对象添加进单例池;
- 为了保持bean的单例性,会调用this.earlySingletonObjects.remove(beanName)和this.singletonFactories.remove(beanName)把二级缓存和三级缓存的该bean对象删除(即使里面没有,但是为了保持bean的单例性就要这样做)
- 最后调用this.registeredSingletons.add(beanName)说明这个bean已经被注册。
addSingleton添加单例bean底层源码
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}
- 首先会把单例池锁住(防止线程不安全,虽然说其实现是ConcurrentHashMap);
- 把beanName和singletonObject放入单例池;
- 与此同时会通过beanName移除二级缓存以及三级缓存对应的数据(保持单例性)
- 最后把beanName放入registeredSingletons集合,说明该bean已经注册成功。
addSingletonFactory添加单例工厂源码
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(singletonFactory, "Singleton factory must not be null");synchronized (this.singletonObjects) {if (!this.singletonObjects.containsKey(beanName)) {this.singletonFactories.put(beanName, singletonFactory);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}}}
- 首先判断单例工厂不能为空,其次就锁住单例池;
- 如果单例池没有这个bean对象,则会往三级缓存放单例工厂;
- 同时会通过这个beanName移除对应的二级缓存数据;
- 且标记为已注册。
为什么这段代码仅仅是移除二级缓存数据?
因为我们是在判断单例池(一级缓存)没有该数据的时候才会往三级缓存放单例工厂,此时又因为我们在一开始就把单例池给锁住,此时是线程安全的,且一级缓存本来就没有该数据,所以不需要多此一举。
getSingleton(String beanName, boolean allowEarlyReference)底层源码
/** * Return the (raw) singleton object registered under the given name. * Checks already instantiated singletons and also allows for an early * reference to a currently created singleton (resolving a circular reference). * @param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */
@Nullableprotected Object getSingleton(String beanName, boolean allowEarlyReference) {// Quick check for existing instance without full singleton lockObject singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {synchronized (this.singletonObjects) {// Consistent creation of early reference within full singleton locksingletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}}}return singletonObject;}
public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName);}
- 首先会通过beanName去单例池(一级缓存)里面取singletonObject;
- 如果取不到(singletonObject==null),并且这个bean正在创建中(isSingletonCurrentlyInCreation(beanName)==true),此时就会去二级缓存里面找;
- 如果二级缓存找不到,并且允许提前引用(allowEarlyReference==true),此时就会锁住单例池;
- 然后再此从单例池中找,找不到的话就会去二级缓存找;
- 二级缓存找不到的话,就会通过beanName拿到单例工厂,如果该单例工厂存在(一般都会存在);
- 就会通过singletonFactory.getObject()去拿到半成品的bean(也就是没有进行完整bean的生命周期的bean),并且放到二级缓存中,同时三级缓存将会删除掉这个单例工厂。
深入Spring源码解析三级缓存(单例工厂)什么时候提前添加bean对象
AbstractAutowireCapableBeanFactory类
doCreateBean部分核心方法
// Eagerly cache singletons to be able to resolve circular references// even when triggered by lifecycle interfaces like BeanFactoryAware.boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) {if (logger.isTraceEnabled()) {logger.trace("Eagerly caching bean '" + beanName +"' to allow for resolving potential circular references");}addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}
- 这段代码就展示了bean对象在什么条件下会添加到三级缓存来解决循环依赖:
- 首先会进行如下三个条件判断(并且只要有一个不符合,该bean就不会提前放到三级缓存中):
- 1:该Bean必须是单例;
- 2:必须允许循环依赖(只有允许了循环依赖,Spring才会出手解决循环依赖问题);
- 3:这个bean必须正在被创建(就是说这个bean还没创建完,此时可能出现了循环依赖现象)
符合了上面三个条件(必须单例、必须允许循环依赖、该bean必须正在被创建),就会提前把不完整对象封装成一个单例工厂放到三级缓存中。