• Spring源码之循环依赖


    https://www.cnblogs.com/longy2012/articles/12834762.html
    https://www.bilibili.com/video/BV1iD4y1o7pM?p=7
    https://www.jianshu.com/p/8bb67ca11831
    https://cloud.tencent.com/developer/article/1497692
    https://blog.nowcoder.net/n/2bb528b258b44c7eab1703a52170ef09

    总结

    1. 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(a)加入到singletonsCurrentlyInCreation set集合中
    2. A进行实例化(未初始化)
    3. A加入三级缓存singletonFactories中
    4. 在AbstractAutowireCapableBeanFactory中populateBean方法中开始属性填充(field B)(调用AutowiredAnnotationBeanPostProcessor类中postProcessProperties方法)
    5. 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(b)加入到singletonsCurrentlyInCreation set集合中
    6. 将B加入singletonsCurrentlyInCreation,标志为正在创建中
    7. B进行实例化(未初始化)
    8. B加入三级缓存singletonFactories中
    9. 开始对B类进行属性填充(A field)
    10. 重新走到AbstractBeanFactory中doGetBean方法,调用DefaultSingletonBeanRegistry类getSingleton方法,将A put到二级缓存earlySingletonObjects中,并在三级缓存singletonFactories中移除
    11. B进行初始化
    12. getSingleton方法中调用DefaultSingletonBeanRegistry类afterSingletonCreation方法,将beanName(b)从singletonsCurrentlyInCreation移除
    13. 走到DefaultSingletonBeanRegistry中getSingleton方法finally中,将B加入一级缓存,并从三级缓存中移除
    14. 将B返回,A进行初始化
    15. getSingleton方法中调用DefaultSingletonBeanRegistry类afterSingletonCreation方法,将beanName(a)从singletonsCurrentlyInCreation移除
    16. 最后走到DefaultSingletonBeanRegistry中getSingleton方法finally中,将A加入一级缓存,并从二级缓存中移除

    示例

    1. @DependsOn
    @DependsOn("b")
    @Component
    public class A {
    }
    
    @DependsOn("a")
    @Component
    public class B {
    }
    

    报错:

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'b' defined
    
    1. field属性注入循环依赖(不报错)
    @Component
    public class A {
        @Autowired
        private B b;
    }
    
    @Component
    public class B {
        @Autowired
        private A a;
    }
    

    源码解析

    三级缓存

    DefaultSingletonBeanRegistry类中:

    	/** Cache of singleton objects: bean name to bean instance. */
    	//一级缓存
    	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
    	/** Cache of singleton factories: bean name to ObjectFactory. */
    	//三级缓存
    	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
    	/** Cache of early singleton objects: bean name to bean instance. */
    	//二级缓存
    	private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
    
    
    springboot中入口

    调用链:
    SpringApplication#run() --> SpringApplication#refreshContext() --> SpringApplication#refresh() --> ServletWebServerApplicationContext#refresh() --> AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean()

    将beanName(a)加入到singletonsCurrentlyInCreation

    AbstractBeanFactory#doGetBean()方法中:

    if (!typeCheckOnly) {
    	markBeanAsCreated(beanName);
    }
    

    markBeanAsCreated方法中:

    this.alreadyCreated.add(beanName);
    

    在getSingleton方法中,执行

    beforeSingletonCreation(beanName);
    
    this.singletonsCurrentlyInCreation.add(beanName)
    

    其中singletonsCurrentlyInCreation为

    /** Names of beans that are currently in creation. */
    private final Set<String> singletonsCurrentlyInCreation =
    		Collections.newSetFromMap(new ConcurrentHashMap<>(16));
    
    A进行实例化(未初始化)

    在在getSingleton方法执行到

    singletonObject = singletonFactory.getObject();
    

    调用匿名方法

    () -> {
        	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;
        	}
        }
    

    调用AbstractAutowireCapableBeanFactory#createBean() --> AbstractAutowireCapableBeanFactory#doCreateBean(),执行如下代码进行实例化:

    if (instanceWrapper == null) {
    	instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    Object bean = instanceWrapper.getWrappedInstance();
    

    bean(A)具备地址

    A加入三级缓存singletonFactories中
    // 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));
    }
    
    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);
    		}
    	}
    }
    
    在populateBean方法中开始对A属性填充
    populateBean(beanName, mbd, instanceWrapper);
    
    对B重复上面步骤

    调用链

    AbstractApplicationContext#refresh() --> AbstractApplicationContext#finishBeanFactoryInitialization() --> DefaultListableBeanFactory#preInstantiateSingletons() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean() --> AbstractAutowireCapableBeanFactory#createBean()
    --> AbstractAutowireCapableBeanFactory#doCreateBean()

    (上面为A,下面开始A属性B注入)
    --> AbstractAutowireCapableBeanFactory#populateBean() --> AutowiredAnnotationBeanPostProcessor#postProcessProperties() --> InjectionMetadata#inject() --> AutowiredAnnotationBeanPostProcessor#inject() --> DefaultListableBeanFactory#resolveDependency() --> DefaultListableBeanFactory#doResolveDependency() --> DependencyDescriptor#resolveCandidate() --> AbstractBeanFactory#getBean() --> AbstractBeanFactory#doGetBean()

    会和上面A同样做下面这些操作:

    • 在DefaultSingletonBeanRegistry类getSingleton方法中将beanName(b)加入到singletonsCurrentlyInCreation set集合中
    • 将B加入singletonsCurrentlyInCreation,标志为正在创建中
    • B进行实例化(未初始化,具有B地址)
    • B加入三级缓存singletonFactories中
    • 开始对B类进行属性填充(A field)
    将A put到二级缓存earlySingletonObjects中

    重新对A执行doGetBean方法,执行getSingleton时,singletonFactory != null,故A放到二级缓存中,并从三级缓存中移除

    Object sharedInstance = getSingleton(beanName);
    
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    	// Quick check for existing instance without full singleton lock
    	Object 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 lock
    				singletonObject = 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;
    }
    
    B进行初始化

    此时B完成属性注入,A具有地址,开始初始化:

    // Initialize the bean instance.
    Object exposedObject = bean;
    try {
    	populateBean(beanName, mbd, instanceWrapper);
    	exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    
    将beanName(b)从singletonsCurrentlyInCreation移除

    B执行完AbstractBeanFactory类匿名方法中createBean(beanName, mbd, args),接着getSingleton往下执行,在finally中:

    finally {
    	if (recordSuppressedExceptions) {
    		this.suppressedExceptions = null;
    	}
    	afterSingletonCreation(beanName);
    }
    
    protected void afterSingletonCreation(String beanName) {
    	if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
    		throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    	}
    }
    
    将B加入一级缓存,并从三级缓存中移除

    在getSingleton方法执行addSingleton(beanName, singletonObject);从而将B从三级缓存中移除,并添加到一级缓存中

    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);
    	}
    }
    
    完成A中B属性注入,对A进行初始化

    A开始执行下面代码:

    exposedObject = initializeBean(beanName, exposedObject, mbd);
    
    开始将beanName(a)从singletonsCurrentlyInCreation移除;并从二级缓存中移除,添加到一级缓存

    A接着getSingleton往下执行,在finally中执行afterSingletonCreation将beanName(a)从singletonsCurrentlyInCreation移除;
    最后在addSingleton(beanName, singletonObject)将A从二级缓存中移除,添加到一级缓存

    面试问题

    • 一级缓存是否够用?

    不能。多线程情况下,会获取到实例化但没有初始化的对象,属性都为null

    • 二级缓存是否够用?

    如果创建是普通类,二级缓存满足

    • 为什么需要三级缓存?(代理)

    在动态代理中,返回是代理类。如果没有三级缓存,最开始放置是实例化好对象,然后缓存有了,后面进行代理处理,那原来的对象是否覆盖??

    	/**
    	 * Obtain a reference for early access to the specified bean,
    	 * typically for the purpose of resolving a circular reference.
    	 * @param beanName the name of the bean (for error handling purposes)
    	 * @param mbd the merged bean definition for the bean
    	 * @param bean the raw bean instance
    	 * @return the object to expose as bean reference
    	 */
    	protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    		Object exposedObject = bean;
    		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    			for (BeanPostProcessor bp : getBeanPostProcessors()) {
    				if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
    					SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
    					exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
    				}
    			}
    		}
    		return exposedObject;
    	}
    
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出。
  • 相关阅读:
    tomcat自启动的最简单的方法
    Eclipse引入DTD文件
    MyBatis框架之基本知识介绍
    【转】Linux系统安装Redis详细过程
    Spring MVC + Spring + MyBatis 框架整合
    Spring框架之IoC和AOP
    Mysql 时间相关
    【转】Spring事务详解
    Spring的注解问题
    关于Calendar的一些用法总结
  • 原文地址:https://www.cnblogs.com/caozibiao/p/13964107.html
Copyright © 2020-2023  润新知