• 【Spring源码解析】Bean循环依赖


    1.什么是循环依赖
    ....
    2.Spring Bean循环依赖
    2.1 不能解决:构造器注入循环依赖;
    根本原因:Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。
    而构造器是完成实例化的东东,所以构造器的循环依赖无法解决~~~
    加入singletonFactories三级缓存的前提是执行了构造器,所以构造器的循环依赖没法解决
    2.2 prototype模式field属性注入循环依赖
    2.3 能解决:singleton模式field属性注入(或setter方法注入)循环依赖
    3.测试demo
    3.1 spring-bean-circular-references.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="a" class="spring.circularreferences.A">
            <property name="b" ref="b" />
        </bean>
        <bean id="b" class="spring.circularreferences.B">
            <property name="a" ref="a" />
        </bean>
    </beans>
    

    3.2 CircularReferencesTest.java

    public class CircularReferencesTest {
        
        @Test
        public void test01() {
            ClassPathResource resource = new ClassPathResource("spring-bean-circular-references.xml");
            DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
            XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
            reader.loadBeanDefinitions(resource);
        
            A a = (A)factory.getBean("a");
            B b = (B)factory.getBean("b");
            Assert.assertEquals(a,b.getA());
            Assert.assertEquals(b,a.getB());
        }
    }
    
    1. 源码部分解析
      4.1 三级缓存,参考DefaultSingletonBeanRegistry.java
    /** 一级缓存:存放完全实例化属性赋值完成的Bean,直接可以使用 **/
    /** Cache of singleton objects: bean name --> bean instance */
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    /** 三级缓存:singletonFactories,三级缓存,存放实例化完成的Bean工厂 **/
    /** Cache of singleton factories: bean name --> ObjectFactory */
    private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    /** 二级缓存:earlySingletonObjects,存放早期Bean的引用,尚未属性装配的Bean **/
    /** Cache of early singleton objects: bean name --> bean instance */
    private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    
    

    4.2 流程

    • getBean(...); // AbstractBeanFactory类 198行
    • doGetBean(...) // AbstractBeanFactory类 239行
    • getSingleton(beanName) // AbstractBeanFactory类 246行
    • getSingleton(beanName,()->{...})// AbstractBeanFactory类 315行
    • singletonFactory.getObject();// AbstractBeanFactory类 222行
    • createBean();// AbstractAutowireCapableBeanFactory类 456行
    • doCreateBean()// AbstractAutowireCapableBeanFactory类 526行
    • addSingletonFactory()// AbstractAutowireCapableBeanFactory类 566行
    • populateBean()// AbstractAutowireCapableBeanFactory类 572行


    4.3 实例化Bean

    // Create bean instance. 实例化Bean
    if (mbd.isSingleton()) {
    	sharedInstance = getSingleton(beanName, () -> {
    		try {
    			return createBean(beanName, mbd, args);
    		}
    		catch (BeansException ex) {
    			// Explicitly remove instance from singleton cache: It might have been put there
    			// eagerly by the creation process, to allow for circular reference resolution.
    			// Also remove any beans that received a temporary reference to the bean.
    			destroySingleton(beanName);
    			throw ex;
    		}
    	});
    	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
    }
    

    4.4 getSingleton 获取实例对象

    /**
     * Return the (raw) singleton object registered under the given name.
     * <p>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
     */
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    	//先从一级缓存中获取已经实例化属性赋值完成的Bean
    	Object singletonObject = this.singletonObjects.get(beanName);
    	//一级缓存不存在,并且Bean正处于创建的过程中
    	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    		synchronized (this.singletonObjects) {
    			//从二级缓存中查询,获取Bean的早期引用,实例化完成但是未赋值完成的Bean
    			singletonObject = this.earlySingletonObjects.get(beanName);
    			//二级缓存中不存在,并且允许创建早期引用(二级缓存中添加)
    			if (singletonObject == null && allowEarlyReference) {
    				//从三级缓存中查询,实例化完成,属性未装配完成
    				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    				if (singletonFactory != null) {
    					singletonObject = singletonFactory.getObject();
    					//二级缓存中添加
    					this.earlySingletonObjects.put(beanName, singletonObject);
    					//从三级缓存中移除
    					this.singletonFactories.remove(beanName);
    				}
    			}
    		}
    	}
    	return singletonObject;
    }
    

    4.5 addSingletonFactory

    	/**
    	 * Add the given singleton factory for building the specified singleton
    	 * if necessary.
    	 * <p>To be called for eager registration of singletons, e.g. to be able to
    	 * resolve circular references.
    	 * @param beanName the name of the bean
    	 * @param singletonFactory the factory for the singleton object
    	 */
    	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);
    			}
    		}
    	}
    
    1. 参考
  • 相关阅读:
    Grid表格的js触发事件
    C# 在获得鼠标点击事件时,如何判断Control键,Shift键被按下
    纠错《COM技术内幕》之ProgID
    C# 日期格式化
    C# 操作系统防火墙
    C# 开发和调用Web Service
    谓侠
    高维FWT
    单位根反演
    容斥 反演
  • 原文地址:https://www.cnblogs.com/zendwang/p/spring-bean-circular-references.html
Copyright © 2020-2023  润新知