zoukankan      html  css  js  c++  java
  • 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 id="prototypeA" class="com.xxx.spring.demo.circularDep.PrototypeA" scope="prototype">
    		<property name="b" ref="prototypeB"/>
    	</bean>
    	<bean id="prototypeB"  class="com.xxx.spring.demo.circularDep.PrototypeB" scope="prototype">
    		<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?
  • 相关阅读:
    leetcode 之Jump Game
    leetcode 之 Symmetric Tree
    leetcode 之 House Robber
    设计模式之建造者模式
    centos7 yum tab 补全
    设计模式之适配器模式
    设计模式之状态模式
    设计模式之外观模式
    设计模式之模板方法模式
    对以<uses-permission android:maxSdkVersion="xx" /> 中的说明
  • 原文地址:https://www.cnblogs.com/yangweiqiang/p/13524731.html
Copyright © 2011-2022 走看看