• spring源码解决循环引用思想


    开发过程中,经常存在类似于A->B,B->A的情况;详见spring源码 DefaultSingletonBeanRegistry的

    getSingleton(String beanName, boolean allowEarlyReference)方法:
    /**
    	 * spring循环引用的处理思路: 允许提前执行引用当前创建的单例对象,
    	 * 此时提前引用的单例对象的属性注入还未完成,因此可以解决循环引用的问题
    	 * 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
    		// isSingletonCurrentlyInCreation 判断对应的单例对象是否在创建中
    		Object singletonObject = this.singletonObjects.get(beanName);
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			synchronized (this.singletonObjects) {
    				// earlySingletonObjects中保存所有提前曝光的单例,尝试从earlySingletonObjects中找
    				singletonObject = this.earlySingletonObjects.get(beanName);
    				if (singletonObject == null && allowEarlyReference) {
    					// 如果允许早期依赖,可以尝试从singletonFactories中找到对应的单例工厂
    					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    					if (singletonFactory != null) {
    						//创建bean,并缓存提前曝光的bean,就是还未进行属性注入的bean,用于解决循环依赖
    						singletonObject = singletonFactory.getObject();
    						this.earlySingletonObjects.put(beanName, singletonObject);
    						this.singletonFactories.remove(beanName);
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
    

      

    说明:

      

    	/** Cache of singleton objects: bean name to bean instance. */
    	/** 缓存单例bean */
    	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. */
    	/** 缓存提前曝光的单例bean 即还未完成属性注入的bean */
    	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
    
    	/** Set of registered singletons, containing the bean names in registration order. */
    	private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
    

    ObjectFactory 接口的getObject()方法:

    public interface ObjectFactory<T> {
    
    	/**
    	 * 此方法返回被bean工厂管理的bean的实例
    	 * Return an instance (possibly shared or independent)
    	 * of the object managed by this factory.
    	 * @return the resulting instance
    	 * @throws BeansException in case of creation errors
    	 */
    	T getObject() throws BeansException;
    
    }
    

     

    @Component
    public  class A {
    	@Autowired
    	private B b;
    	
    }
    
    @Component
    public class B {
    
    	@Autowired
    	private A a;
    }
    

     1、首先创建A的实例a,然后对a做属性填充B

     2、此时发现需要创建B的实例b,创建实例b,

     3、对b做属性填充,发现需要A的实例;此时A的实例对象a正在创建中,此时B的对象b会设置属性A a=null;以用来完成B的实例化成功 

     4、B实例化对象b完成;设置A实例化对象a的b属性;完成a的实例化;

      

    循环引用的解决方案:

        1 使用@Autowired 注解,由spring决定对象属性的注入时机,先暴露对象A的引用,在需要的时候在注入对象B;

        2  基于setter方法注入属性B

  • 相关阅读:
    js调用手机震动
    模拟器 Android Studio
    不修改代码,让调用方法 替换到另外一个方法
    springboot 获取请求 / 响应 接收和设置请求头 、请求码的方法
    mysql binlog 实现数据库同步先占位 有空研究下
    Airtest无线连接android手机
    springboot + spring cloudeureka
    更新一条数据多个字段的方法
    PyAutoGUI 操作C端 识别图片 点击(有空就看一下) 可以替代 Autoit
    playwright入门
  • 原文地址:https://www.cnblogs.com/wl20200316/p/12516384.html
Copyright © 2020-2023  润新知