Spring循环引用

一、 Spring循环依赖问题

什么是循环引用:在A Service中引用了B,在B Service中引用了A,形成了一个闭环的情况。

spring为我们解决了这一个问题,前提是需要将bean的scope设置为singleton,如果设置为prototype则会报错,因为非单例的bean不会放入缓存中。spring主要是通过三级缓存来解决这个问题。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	/** 一级缓存,也叫单例池,存放已经经历完整声明周期的Bean */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

	/** 三级缓存,存放可以生成bean的工厂 */
	private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

	/** 二级缓存,存放早期暴露的bean,就是bean的属性尚未填装完毕 */
	private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
}

二、Spring循环依赖源码解读:

通过 ClassPathXmlApplicationContext 的构造方法进行了spring的初始化操作

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
	super(parent);
	setConfigLocations(configLocations);
	if (refresh) {
    	refresh();  // 这里进行了spring的初始化
	}
}

进入refresh方法就可以看到spring的主要加载方法,

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        
     // 进行容器的初始化,并且加载bean
     finishBeanFactoryInitialization(beanFactory);
    }
}

这里主要看循环引用的地方

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {	
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}
	beanFactory.setTempClassLoader(null);
	beanFactory.freezeConfiguration();

	// 对所有的非懒加载的bean进行操作
	beanFactory.preInstantiateSingletons();
}

进入到 preInstantiateSingletons 这个里

public void preInstantiateSingletons() throws BeansException {
    // 从beanDefinition中获取需要加载bean的信息
    List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

    // 加载bean
    for (String beanName : beanNames) {
        RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
        // 判断是否是抽象的,是不是单例,是不是懒加载
        if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
            if (isFactoryBean(beanName)) {
                ... // 代码省略 如果是工厂bean
            }
            else {
                getBean(beanName);  // 通过beanName获取bean
            }
        }
    }
}

去获取bean,在spring中以do开头的方法一般都是真正处理的地方

public Object getBean(String name) throws BeansException {
    return doGetBean(name, null, null, false);
}

 这里只看单例bean的情况,因为只有单例bean才可以解决循环引用的问题。

protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
    // 检验是否存在alias 别名的配置
    String beanName = transformedBeanName(name);
    Object bean;

    // 从一级缓存中查找
    Object sharedInstance = getSingleton(beanName);
    if (sharedInstance != null && args == null) {
        // 当循环引用的时候回走到这个分支,进行完善,返回bean
        bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
    }
    else {
        try {
            // 通过beanDefine获取bean对象的信息
            RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
            checkMergedBeanDefinition(mbd, beanName, args);

            // 关于bean的依赖
            String[] dependsOn = mbd.getDependsOn();
            if (dependsOn != null) {
                for (String dep : dependsOn) {
                    registerDependentBean(dep, beanName);
                    try {
                        getBean(dep);
                    }
                }
            }
            
            if (mbd.isSingleton()) {
                // 只有单例模式,spring才会自动解决循环引用的问题,单例模式进行获取bean
                sharedInstance = getSingleton(beanName, () -> {
                    try {
                        return createBean(beanName, mbd, args);
                    }
                });
                bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
            }
        }
    }
    return (T) bean;
}

首先,先看从一级缓存中查找

public Object getSingleton(String beanName) {
	return getSingleton(beanName, true);
}

老规矩,继续翻,这里第一次进入,会直接返回null,主要是第二次循环引用来的时候。

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 从一级缓存中获取bean,刚开始肯定获取不到,直接返回null
	Object singletonObject = this.singletonObjects.get(beanName);

    // 判断一级缓存中是否有该bean,以及该bean是否正在被创建
    // 当循环引用的时候 A-->B  B-->A ,当A作为属性初始化的时,isSingletonCurrentlyInCreation这个返回的是false
	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) {
                    // 这里执行的是之前存放的lambda表达式,代码说明放到最后
					singletonObject = singletonFactory.getObject();
                    // 把A放到二级缓存
					this.earlySingletonObjects.put(beanName, singletonObject);
                    // 把三级缓存的A删掉
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}

为null返回以后继续向下走,到 getSingleton ,这里还传入一个lambda表达式

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	synchronized (this.singletonObjects) {
        // 从一级缓存获取,第一次来根本获取不到
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
			... // 代码省略
			try {
                // 这里直接到了createBean这个传入的方法
				singletonObject = singletonFactory.getObject();
				newSingleton = true;
			}
				
			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
                // 加入到单例池中,放在最后讲解
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

通过打断点可以知道getObject方法就是去执行传入的lambda表达式,createBean方法,Spring所有的后置处理器(BeanFactoryPostProcessor)所有的目的只有一个就是为了扩展实现。

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    // 解决lookup method和 replace-up method的方法
    mbdToUse.prepareMethodOverrides();

    // 第一次应用spring的后置处理器 InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation
    // 这里也是解析AOP并将AOP放入缓存的地方
    Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

    // 创建bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
}

这里主要就是将创建的bean放入三级缓存,并开始填充属性。

protected Object doCreateBean(...) throws BeanCreationException {
	... // 代码省略
	instanceWrapper = createBeanInstance(beanName, mbd, args);

    if (instanceWrapper == null) {
        // 第二次调用后置处理器,主要是解决使用哪个构造方法
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}

    // 第三个后置处理器,调用MergedBeanDefinitionPostProcessor的postProcessMergedBeanDefinition方法
    applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    ... // 代码省略

    // 是否是单例, allowCircularReferences 默认是true
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {	
        //  主要是将创建的bean添加到三级缓存,并把lambda表达式也存起来
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
    }

    Object exposedObject = bean;
	try {
        // 填装属性
		populateBean(beanName, mbd, instanceWrapper);

		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
}

首先,看如何初始化一个bean,直接到最后一行代码。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    ... // 代码省略
    
    // 调用 SmartInstantiationAwareBeanPostProcessor 的 determineCandidateConstructors后置处理器
    Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);

    ... // 代码省略
    return instantiateBean(beanName, mbd);
}

底层是通过反射创建的bean

protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
    try {
        Object beanInstance;
        if (System.getSecurityManager() != null) {
            beanInstance = AccessController.doPrivileged(
                    (PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
                    getAccessControlContext());
        }
        else {
            // 初始化bean
            beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
        }
    }
}
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
    
    ... // 代码省略
    if (System.getSecurityManager() != null) {
        constructorToUse = AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
      }
    else {
        // 反射获取到class对象
        constructorToUse = clazz.getDeclaredConstructor();
     }
    return BeanUtils.instantiateClass(constructorToUse); // new一个对象
}

最后通过BeanUtil去调用newInstance

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
    ... // 代码省略
     // 反射去创建对象
    return ctor.newInstance(argsWithDefaultValues);
}

然后回过来看放入三级缓存

protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {synchronized (this.singletonObjects) {
    // 检查是否在一级缓存
	if (!this.singletonObjects.containsKey(beanName)) {
		this.singletonFactories.put(beanName, singletonFactory);  // 添加到三级缓存,并存lambda表达式
		this.earlySingletonObjects.remove(beanName);   // 从二级缓存移除
		this.registeredSingletons.add(beanName); 
	}
}

开始填充属性

protected void populateBean(...) {
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 第五次调用后置处理器 InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
				InstantiationAwareBeanPostProcessor ibp =(InstantiationAwareBeanPostProcessor) bp;
                // 判断是否要填装属性
				if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}
	}
    
    // 获取属性
    PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
    
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
        // 第六次调用后置处理器  主要是解决填装问题
        // InstantiationAwareBeanPostProcessor的postProcessProperties
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp =(InstantiationAwareBeanPostProcessor) bp;
			PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				if (filteredPds == null) {
					filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
				}
				pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					return;
				}
			}
			pvs = pvsToUse;
		}
	}

    // 属性填装
    applyPropertyValues(beanName, mbd, bw, pvs);
}
protected void applyPropertyValues(...) {
    // 用于存放相关联的属性
    List<PropertyValue> original;  
	if (pvs instanceof MutablePropertyValues) {
		mpvs = (MutablePropertyValues) pvs;
		original = mpvs.getPropertyValueList();
	}
	else {
		original = Arrays.asList(pvs.getPropertyValues());
	}

    for (PropertyValue pv : original) {		
	    // 如果service B 还没有创建那就去创建
        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
    }
    // 属性赋值
    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}

初始作为属性注入的bean

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
    if (value instanceof RuntimeBeanReference) {
		RuntimeBeanReference ref = (RuntimeBeanReference) value;
		return resolveReference(argName, ref);
	}
    ... // 代码省略
}
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    // 判断是否有父工厂
    if (ref.isToParent()) {...}
    else{
        // 判断有没有beanType,beanType 是ref的属性,ref是Service B,因为假设Service A引用 Service B,需要填装service B,B还没有初始化,在这里进行初始化
        if (beanType != null) {...}
		else {
			resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
			bean = this.beanFactory.getBean(resolvedName);  // 这里又绕到了前面的doGetBean,获取到引用的A
		}
    }
}

这里又回到之前的getBean方法去创建B 这个Bean,当填充属性A bean的时候就会继续去获取bean A,但是这次能在三级缓存中获取到bean A于是在getSingleton 方法中走保存的lambda表达式。

protected Object getEarlyBeanReference(...) {
	Object exposedObject = bean;
	if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
            // 第四次执行后置处理器 SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
				exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
			}
		}
	}
	return exposedObject;
}

在填充完属性以后 initializeBean 中调用后置处理器,还有一个后置处理在销毁(close)的时候调用,一共九个后置处理器。

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    // 执行所有实现了aware的接口,这里不会设置environment因为之前设置了忽略
    // 只会对实现BeanNameAware、BeanClassLoaderAware、BeanFactoryAware三个接口进行设置
    invokeAwareMethods(beanName, bean);

    if (mbd == null || !mbd.isSynthetic()) {
       // 第七次后置处理器  BeanPostProcessor 的 postProcessBeforeInitialization
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }

    if (mbd == null || !mbd.isSynthetic()) {
        // 第八次后置处理器  BeanPostProcessor 的 postProcessAfterInitialization
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }
    return wrappedBean;
}

最后会放入到单例池中,迁移到一级缓存

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);     // 添加注册bean
	}
}

总之就是一个俄罗斯套娃的形式,具体如图:

11d6e7b6116b6ff2ccb3a37beb457352.png

※:关于三级缓存的问题,三级缓存的关键? 三级缓存能不能换成二级缓存?

三级缓存的关键是 实例化和初始化分开操作。

三级缓存的意义是存在代理,如果只用二级缓存的话(一个存放半成品,一个存放成品),如果要是有代理对象需要一层覆 盖掉原来的,所以又加了一层,形成三级(一个存放代理用于覆盖半成品,一个存放半成品,一个存放成品)。

在普通的循环依赖的情况下,三级缓存没有任何作用。三级缓存实际上跟Spring中的AOP相关。AOP场景下的getEarlyBeanReference 会拿到一个代理的对象,但是不确定有没有依赖,需不需要用到这个依赖对象,所以先给一个工厂放到三级缓存里。

这个工厂的目的在于延迟对实例化阶段生成的对象的代理,只有真正发生循环依赖的时候,才去提前生成代理对象,否则只会创建一个工厂并将其放入到三级缓存中,但是不会去通过这个工厂去真正创建对象。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值