Spring三级缓存解决循环依赖

Spring三级缓存解决循环依赖

三级缓存的定义

答案就在DefaultSingletonBeanRegistry的注释里面.....

	/**
	 * 一级缓存 存放完全初始化好的对象, 拿来可以直接使用
	 */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/**
	 * 二级缓存 存放还未完成初始化好的对象, 从三级缓存拿出后,放到二级里面
	 */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

	/**
	 * 三级缓存 存放beanName-> ObjectFactory的匿名内部类
	 * 何时添加三级缓存:DefaultSingletonBeanRegistry#addSingletonFactory(java.lang.String, org.springframework.beans.factory.ObjectFactory)
	 * 匿名干的事儿:AbstractAutowireCapableBeanFactory#getEarlyBeanReference(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object)
	 * 解决代理对象的问题
	 * A 依赖 B,把A的ObjectFactory匿名内部类放到三级缓存
	 * 创建B,B依赖A,从三级缓存拿到匿名内部类,然后调用getObject方法,如果A是简单普通对象,直接返回a, 如果A需要代理,则返回代理对象
放到二级缓存的意义:如果A是一个被aop代理的对象, 为了保证拿到的都是同一个代理对象,第一次调用获取三级缓存对象之后,就把它放到二级缓存。 
	 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	

	/** Names of beans that are currently in creation */
  /**
	 * 在创建单例bean之前加入到set集合中
	 */
	private final Set<String> singletonsCurrentlyInCreation =
			Collections.newSetFromMap(new ConcurrentHashMap<>(16));

源码中的步骤

入口:

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
   
    //忽略其他代码
  }

获取bean的过程,一级,二级,三级
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

/**
	 * 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) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				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;
	}

Spring 不能解决哪种循环依赖

构造器依赖

// PrototypeA 构造器 B
public PrototypeA(PrototypeB b) {
    this.b = b;
}

// PrototypeB 构造器 需要A
public PrototypeB(PrototypeA a) {
    this.a = a;
}

报错:

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'prototypeB' defined in class path resource [beans.xml]: 
Cannot resolve reference to bean 'prototypeA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeA': Requested bean is currently in creation: Is there an unresolvable circular reference?

原型类型的依赖

public class PrototypeA {
    private PrototypeB b;//A->B

    public PrototypeB getB() {
        return b;
    }

    public void setB(PrototypeB b) {
        this.b = b;
    }
}

public class PrototypeB {
    private PrototypeA a ;//B->A

    public PrototypeA getA() {
        return a;
    }

    public void setA(PrototypeA a) {
        this.a = a;
    }
}

x m l配置

	<!-- scope都是原型prototype -->
  <bean >
		<property name="b" ref="prototypeB"/>
	</bean>
	<bean >
		<property name="a" ref="prototypeA"/>
	</bean>

报错:

Caused by: org.springframework.beans.factory.BeanCreationException: 
Error creating bean with name 'prototypeB' defined in class path resource [beans.xml]: 
Cannot resolve reference to bean 'prototypeA' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'prototypeA': Requested bean is currently in creation: Is there an unresolvable circular reference?