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

posted @ 2020-03-18 11:39  wl_王麟  阅读(762)  评论(0编辑  收藏  举报