5.SpringIOC源码-Bean循环依赖讲解

5.SpringIOC源码-Bean循环依赖讲解

1. 0前序

​ 在IOC容器中,Bean的声明周期中(Bean 实例化->属性赋值->初始化->添加到一级缓存),BeanA创建的时候,可能会依赖另一BeanB,BeanB创建的时候依赖BeanA,这时就会产生循环依赖,下面我们看看Spring是怎么解决循环依赖的。

如下图
在这里插入图片描述

2.0 手写Spring循环依赖

前置背景:需要下载Spring源码并编译通过。在新建的model中写代码模拟Spring的循环依赖过程,讲解下一级、二级、三级缓存在循环依赖中的作用。

2.1 模拟循环依赖问题

现有对象BeanA和BeanB,模拟循环依赖类BeanInitTest代码如下:

import org.springframework.beans.factory.annotation.Autowired;

public class BeanA {
	@Autowired
	private BeanB beanB;

	public BeanA(){};
	public BeanA(BeanB beanB){
		this.beanB=beanB;
	}

	public BeanB getBeanB() {
		return beanB;
	}

	public void setBeanB(BeanB beanB) {
		this.beanB = beanB;
	}
}
import org.springframework.beans.factory.annotation.Autowired;

public class BeanB {

	@Autowired
	private BeanA beanA;

	public BeanB(BeanA beanA){
		this.beanA = beanA;
	}

	public BeanA getBeanA() {
		return beanA;
	}

	public void setBeanA(BeanA beanA) {
		this.beanA = beanA;
	}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BeanInitTest {
	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

	/**
	 * 读取Bean定义,当然在Spring中肯定是根据配置 动态扫描注册
	 */
	public static void loadBeanDefinitions(){
		RootBeanDefinition aBeanDefinition  = new RootBeanDefinition(BeanA.class);
		RootBeanDefinition bBeanDefinition  = new RootBeanDefinition(BeanB.class);
		beanDefinitionMap.put("beanA",aBeanDefinition);
		beanDefinitionMap.put("beanB",bBeanDefinition);
	}

	public static void main(String[] args) throws Exception {
		//加载BeanDefinitions
		loadBeanDefinitions();
		//注册Bean的后置处理器

		// 循环创建bean
		for(String key :beanDefinitionMap.keySet()){
			//创建A
			getBean(key);
		}
	}

	//一级缓存对象
	public static Map<String,Object> singletonObject = new ConcurrentHashMap<>();

  /**
	*获取bean对象
	*/
	public static Object getBean(String beanName) throws Exception{

		//1.实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instanceBean = beanClass.newInstance();
	//若在此添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整Bean

		//2.属性赋值
		Field[] declaredFields = beanClass.getDeclaredFields();
		for(Field declaredField:declaredFields){
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			//说明属性上面有@Autowired注解
			if(annotation!=null){
				declaredField.setAccessible(true);
				//byName byType byConstrator
				//BeanB
				String name = declaredField.getName();
				//获取BeanB对象
				Object b= getBean(name);
				//设置BeanA对象的BeanB属性
				declaredField.set(instanceBean,b);

			}
		}
		//3.初始化 :模拟时没什么可写的已经创建出对象了

		//4.添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean
		singletonObject.put(beanName,instanceBean);
		return instanceBean;
	}
}

问题描述

上面代码出现的问题是:创建BeanA对象的时候需要依赖BeanB对象,但是创建BeanB对象的时候需要依赖BeanA对象,两个对象互相依赖,上面的代码会形成死循环,最终报错。

如果添加一级缓存的地方是在实例化Bean之后,这个Bean可能不是完整的,因为可能会有其他依赖的属性需要赋值的。

2.2 循环依赖问题解决

循环依赖需要找到一个合适的地方当做循环的出口(终止点),这个位置就是getBean方法的下面,实例化的上面。

如果不添加二级缓存怎么解决循环依赖?

答:把4.添加到一级缓存的代码放到2.填充属性的上面,在BeanInitTest类中添加一个getSigleton() 方法出口,并且在getBea方法最上面调用,这样可以解决循环依赖的问题,代码变动如( 2.2) 标识处(只留重要代码其他省略了)。



public class BeanInitTest1 {
	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

	//一级缓存对象
	public static Map<String,Object> singletonObject = new ConcurrentHashMap<>();
	//获取Bean
	public static Object getBean(String beanName) throws Exception{
		//(2.2) 获取缓存中的bean
		Object object = getSingleton(beanName);
		if(object!=null){
			return object;
		}
		//1.实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instanceBean = beanClass.newInstance();
	//如果添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean
        //(2.2)从4.添加到一级缓存移动到这里
        singletonObject.put(beanName,instanceBean);
        
		//2.属性赋值
		Field[] declaredFields = beanClass.getDeclaredFields();
		for(Field declaredField:declaredFields){
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			//说明属性上面有@Autowired注解
			if(annotation!=null){
				declaredField.setAccessible(true);
				//byName byType byConstrator
				//BeanB
				String name = declaredField.getName();
				//获取BeanB对象
				Object b= getBean(name);
				//设置BeanA对象的BeanB属性
				declaredField.set(instanceBean,b);

			}
		}
		//3.初始化
		//4.添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean
		
		return instanceBean;
	}
	//(2.2)从一级缓存获取
	public static  Object getSingleton(String beanName){
		if(singletonObject.containsKey(beanName)){
			//先去一级缓存拿去
			return singletonObject.get(beanName);
		}
		return null;
	}
}

这样改新的问题了就来了;把添加一级缓存放到了1.实例化后面,放入缓存的对象是没有赋值属性的对象,不完整,这样的对象我们称为了纯净对象;这样虽然解决了循环依赖,但是对象不完整。

接下来我们要引入二级缓存

二级缓存的作用:将完成Bean和纯洁(属性没有赋值)Bean分开,避免读取不完整的Bean。
在这里插入图片描述

代码修改:Bean实例化后,添加到二级缓存,Bean初始化后放入一级缓存,在getSingleton方法中添加如果二级缓存存在直接去二级缓存获取并返回对象。代码修改的地方是(2.3)处。

	//一级缓存对象
	public static Map<String,Object> singletonObject = new ConcurrentHashMap<>();

	//(2.3)二级缓存:为了将完整Bean和纯洁Bean分离(属性没有赋值时),避免读取到不完整Bean
	public static Map<String,Object> earlySingletonObject = new ConcurrentHashMap<>();

	//获取Bean
	public static Object getBean(String beanName) throws Exception{
		//(2.2) 获取缓存中的bean
		Object object = getSingleton(beanName);
		if(object!=null){
			return object;
		}
		//1.实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instanceBean = beanClass.newInstance();
		//如果添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean

		//(2.3)添加二级缓存
		earlySingletonObject.put(beanName,instanceBean);
		//2.属性赋值
		Field[] declaredFields = beanClass.getDeclaredFields();
		for(Field declaredField:declaredFields){
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			//说明属性上面有@Autowired注解
			if(annotation!=null){
				declaredField.setAccessible(true);
				//byName byType byConstrator
				//BeanB
				String name = declaredField.getName();
				//获取BeanB对象
				Object b= getBean(name);
				//设置BeanA对象的BeanB属性
				declaredField.set(instanceBean,b);
			}
		}
		//3.初始化

		//4.添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean
		singletonObject.put(beanName,instanceBean);
		return instanceBean;
	}
	//(2.2)从一级缓存获取
	public static  Object getSingleton(String beanName){
		if(singletonObject.containsKey(beanName)){
			//先去一级缓存拿去
			return singletonObject.get(beanName);
		//(2.3)判断二级缓存是否存在,存在直接从二级缓存中获取
		}else if(earlySingletonObject.containsKey(beanName)){
			return earlySingletonObject.get(beanName);
		}
		return null;
	}
2.3 三级缓存

解耦的方式,通过BeanPostProcessor后置处理器创建的动态代理。

三级缓存的作用:解耦,AOP,存储接口函数的。

整体逻辑描述:添加一个代理类(JdkDynimcProxy),代理类的后置处理器(getEarlyBeanReference),一个接口函数(ObjectFactory),循环标识变量(singletonCurrentlyInCreation);

1)在getBean 方法开始先判断是否有正在创建Bean的标识,如果没有添加到循环标识中;

2)在实例化Bean之后添加三级缓存,对象是通过接口函数创建的(原来二级缓存的地方换成了三级缓存);

3)修改getSingleton方法:查询一级缓存,如果一级缓存不存在且在循环依赖中,查询二级缓存是否有,没有从三家缓存获取,获取之后放入二级缓存中。

4)在Bean的初始化之后添加(如果是动态代理,一级缓存中的对象应该也是动态代理对象);

代码如有(2.4)处的修改:

代理类(JdkDynimcProxy)

public class JdkDynimcProxy  {

	private Object bean;

	public JdkDynimcProxy (Object bean){
			this.bean = bean;
	}
	//生成被代理的对象
	public Object getProxy() throws IllegalAccessException, InstantiationException {
		return bean.getClass().newInstance();
	}
}

代理类的后置处理器(getEarlyBeanReference)

import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
/**
 * 后置处理器
 */
public class JdkProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
	public Object getEarlyBeanReference(Object bean,String beanName) {
		//假如 A 被切点命中 需要创建代理 @PointCut("execution(* *..BeanA.*(..))")
		if(bean instanceof BeanA){
			JdkDynimcProxy jdkDynimcProxy = new JdkDynimcProxy(bean);
			try {
				return jdkDynimcProxy.getProxy();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return bean;
	}
}

接口函数(ObjectFactory)

import org.springframework.beans.BeansException;

@FunctionalInterface
public interface ObjectFactory<T> {

	T getObject() throws BeansException;
}

重点看有(2.4)处

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class BeanInitTest {
	private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

	/**
	 * 读取Bean定义,当然在Spring中肯定是根据配置 动态扫描注册
	 */
	public static void loadBeanDefinitions(){
		RootBeanDefinition aBeanDefinition  = new RootBeanDefinition(BeanA.class);
		RootBeanDefinition bBeanDefinition  = new RootBeanDefinition(BeanB.class);
		beanDefinitionMap.put("beanA",aBeanDefinition);
		beanDefinitionMap.put("beanB",aBeanDefinition);
	}

	public static void main(String[] args) throws Exception {
		//加载BeanDefinitions
		loadBeanDefinitions();
		//注册Bean的后置处理器

		// 循环创建bean
		for(String key :beanDefinitionMap.keySet()){
			//创建A
			getBean(key);
		}
	}

	//一级缓存对象
	public static Map<String,Object> singletonObject = new ConcurrentHashMap<>();

	//二级缓存:为了将完整Bean和纯洁Bean分离(属性没有赋值时),避免读取到不完整Bean
	public static Map<String,Object> earlySingletonObject = new HashMap<>();

	//三级缓存:
	public static Map<String,ObjectFactory> singletonFactories = new HashMap<>();
	//假设A使用了AOP @PointCut("execution(* *..BeanA.*(..))") 要给A创建动态代理
	//循环状态标识
	public static Set<String> singletonCurrentlyInCreation = new HashSet<>();

	//获取Bean
	public static Object getBean(String beanName) throws Exception{

		Object singleton = getSingleton(beanName);
		if(singleton!=null){
			return singleton;
		}
		//(2.4)正在创建
		if(!singletonCurrentlyInCreation.contains(beanName)){
			singletonCurrentlyInCreation.add(beanName);
		}

		//1.实例化
		RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
		Class<?> beanClass = beanDefinition.getBeanClass();
		Object instanceBean = beanClass.newInstance();
		//如果添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean

		// 创建动态代理 (耦合方式,BeanPostProcessor) Spring 还是希望正常的bean 还是在初始化后创建
		//(2.4)只有在循环依赖的情况下在实例化后创建proxy
		Object finalInstanceBean = instanceBean;
		singletonFactories.put(beanName, new ObjectFactory() {
			@Override
			public Object getObject() throws BeansException {
				Object earlyBeanReference = new JdkProxyBeanPostProcessor().getEarlyBeanReference(finalInstanceBean, beanName);
				return earlyBeanReference;
			}
		});
		//添加二级缓存
		// earlySingletonObject.put(beanName,instanceBean);
		//2.属性赋值
		Field[] declaredFields = beanClass.getDeclaredFields();
		for(Field declaredField:declaredFields){
			Autowired annotation = declaredField.getAnnotation(Autowired.class);
			//说明属性上面有@Autowired注解
			if(annotation!=null){
				declaredField.setAccessible(true);
				//byName byType byConstrator
				//BeanB
				String name = declaredField.getName();
				//获取BeanB对象
				Object b= getBean(name);
				//设置BeanA对象的BeanB属性
				declaredField.set(instanceBean,b);

			}
		}
		//3.初始化

		//(2.4)如果是动态代理一级缓存中应该也是
		if(earlySingletonObject.containsKey(beanName)) {
			instanceBean = earlySingletonObject.get(beanName);
		}
		//4.添加到一级缓存 (解决了对象依赖循环但是对象不完整) 并发场景量同时getBean 可能拿到不完整的Bean
		singletonObject.put(beanName,instanceBean);
        //移除二级和三级缓存。未写
		return instanceBean;
	}

	//(2.4)从一级缓存获取
	public static  Object getSingleton(String beanName) throws IllegalAccessException, InstantiationException {
		Object bean = singletonObject.get(beanName);
		//一级缓存没有就说明是循环依赖
		if(bean==null&&singletonCurrentlyInCreation.contains(beanName)){
			//判断二级缓存是否有
			bean = earlySingletonObject.get(beanName);
			//二级缓存没有从三级缓存拿
			if(bean == null) {
				//从三级缓存拿
				ObjectFactory factory = singletonFactories.get(beanName);
				if (factory != null) {
					//放入二级缓存
					earlySingletonObject.put(beanName, factory.getObject());
				}
			}
		}
		return bean;
	}
}
2.4 缓存相关问题

Spring 在什么时候创建动态代理?

分两种情况:正常情况下是在初始化创建动态代理,另一种是若有循环依赖是在实例化之后创建动态代理。

为什么不在实例化之后放入二级缓存?

假设A使用AOP,B依赖A对象,如果在getBean A时在实例化之后把A放入了二级缓存,这时getBean B 复制依赖A的属性时从缓存中获取的并不是A的代理对象,而是A的纯净对象,所以在实例化后不能放入二级缓存。

3.0 循环依赖源码分析

1.实例化容器:AnnotationConfigApplicationContext :

// 加载spring上下文
   AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);

创建AnnotationConfigApplicationContext对象,具体的方法作用都在源码的注释上面

//根据参数类型可以知道,其实可以传入多个annotatedClasses,但是这种情况出现的比较少
    public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        //调用无参构造函数,会先调用父类GenericApplicationContext的构造函数
        //父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory
        //本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,一个扫描器ClassPathBeanDefinitionScanner scanner
        //scanner的用处不是很大,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
        this();
        //把传入的类进行注册,这里有两个情况,
        //传入传统的配置类
        //传入bean(虽然一般没有人会这么做
        //看到后面会知道spring把传统的带上@Configuration的配置类称之为FULL配置类,不带@Configuration的称之为Lite配置类
        //但是我们这里先把带上@Configuration的配置类称之为传统配置类,不带的称之为普通bean
        register(annotatedClasses);
        //刷新
        refresh();
    }

循环依赖是,Bean声明周期里面的,在方法refresh()里面的finishBeanFactoryInitialization方法里。

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			//1.准备刷新上下文环境
			prepareRefresh();
			//2.获取告诉子类初始化Bean工厂 下同工厂不同实现
			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			//3.对Bean工厂进行填充属性
			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				//4.留个子类去实现该接口
				postProcessBeanFactory(beanFactory);
				//调用Bean工厂的后置处理器  1.会在此将class扫描成BeanDefine
				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);
				//注册我们的bean的后置处理器
				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);
				//初始化国际化资源处理器
				// Initialize message source for this context.
				initMessageSource();
				//创建时间多播器
				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();
				//这个方法同时是留个子类实现的SpringBoot也是从这方法进行
				// Initialize other special beans in specific context subclasses.
				onRefresh();
				//把事件监听注册到多播器上
				// Check for listener beans and register them.
				registerListeners();
				//实例化剩余的单实例Bean
				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);
				//最后容器刷新  发布刷新事件(Spring cloud 也是从这里启动的)
				// Last step: publish corresponding event.
				finishRefresh();
			}
		}
	}

finishBeanFactoryInitialization实例化Bean时有循环依赖。

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// Initialize conversion service for this context.
		//为Bean工厂创建类型转化器 Convert
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// Register a default embedded value resolver if no bean post-processor
		// (such as a PropertyPlaceholderConfigurer bean) registered any before:
		// at this point, primarily for resolution in annotation attribute values.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
		//处理关于aspectj
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// Stop using the temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(null);

		// Allow for caching all bean definition metadata, not expecting further changes.
		//冻结所有的Bean定义,说明注册的Bean不做任何修改
		beanFactory.freezeConfiguration();

		// Instantiate all remaining (non-lazy-init) singletons.
		//实例化剩余的单实例bean
		beanFactory.preInstantiateSingletons();
	}

冻结所有的Bean定义,接下来就要实例化Bean, beanFactory.preInstantiateSingletons()

	@Override
	public void preInstantiateSingletons() throws BeansException {
		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		//获取容器中所有的Bean定义的名字
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		//循环所有的Bean定义
		for (String beanName : beanNames) {
			//合并Beand定义,转换为统一的RootBeanDefinition类型,方便后面处理
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//根据bean定义判断不是抽象的,是单例的,不是懒加载的
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//是不是工厂Bean
				if (isFactoryBean(beanName)) {
					//是工厂FactoryBean会生成实际的Bean (beanName 是用来获取实际Bean的)
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						//调用真正的getBean流程
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					//非工厂bean,就是普通Bean
					getBean(beanName);
				}
			}
		}

getBean()方法如下:

	@Override
	public Object getBean(String name) throws BeansException {
		//真正获取Bean的逻辑
		return doGetBean(name, null, null, false);
	}

doGetBean()方法部分代码如下

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		//这里传入的name 可能是别名,也有可能是工厂的Bean的name,所以需要在这里转换
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		//尝试去缓存中获取对象
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

getSingleton() 方法如下

@Override
@Nullable
public Object getSingleton(String beanName) {
    //在这里 系统一般是允许早期对象引用的  allowEarlyReference 通过控制这个参数可以解决循环依赖
    return getSingleton(beanName, true);
}

在网上很多很多写源码的大佬,也没有说清楚为啥要使用三级缓存(二级缓存是否可以把循环依赖解决)答案是:可以,但是没有很好的扩展性为啥这么说…
原因:获取三级缓存-----getEarlyBeanReference()经过一系列的后置处理来给我们早期对象进行特殊化处理从三级缓存中获取包装对象的时候 ,它会经过一次后置处理器的处理对我们早期对象的bean进行 特殊化处理,但是spring的原生后置处理器没有经过处理,而是留给了我们程序员进行扩展
singletonObject =singletonFactory.getObject();把三级缓存移植到二级缓存中
this. earlySingletonObjects.put(beanName, singletonObject);

把三级缓存移植到二级缓存中

this. earlySingletonObjects.put(beanName, singletonObject);

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		/**
		 * 第一步:尝试去一级缓存获取(单例缓存池中获取对象,一般情况下从该map中获取的对象可以直接使用)
		 * IOC容器初始化加载单例Bean的时候,第一次进来的时候 该map中一般返回时空
		 */
		Object singletonObject = this.singletonObjects.get(beanName);
		/**
		 * 若在第一级缓存中没有获取到对象,并且singletonCurrentlyInCreation这个list包含改beanName
		 *  IOC容器初始化加载单实例Bean的时候第一次进来的时候,该list中一般返回空,但是在循环依赖的时候返回时true
		 */
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				/**
				 * 尝试去二级缓存获取对象(二级缓存中的对象是一个早期对象)
				 * 早期对象:就是Bean刚刚调用构造方法,还来不及给Bean的属性赋值的对象(纯净对象)
				 */
				singletonObject = this.earlySingletonObjects.get(beanName);
				/**
				 * 二级缓存中也没有获取到对象,allowEarlyReference 为true 为循环依赖(参数是上个方法传过来的)
				 */
				if (singletonObject == null && allowEarlyReference) {
					/**
					 * 直接从三级缓存中获取,ObjectFactory对象 这个对接就是用来解决循环依赖的关键所在
					 * 在IOC 后期的过程中,当Bean调用构造方法的时候,把早期对象包裹成一个ObjectFactory对象
					 * 暴露在三级缓存中
					 */
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//从三级缓存中获取的对象不为空
					if (singletonFactory != null) {
						/**
						 * 在这里通过暴露ObjectFactory包装对象,在通过调用它的getObject来获取纯净对象
						 *  在这个缓解中调用到 getEarlyReference来进行后置处理
						 */
						singletonObject = singletonFactory.getObject();
						//把早期对象放置在二级缓存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//ObjectFactory 包装对象从三级缓存中删除
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

问题:

Spring有没有解决构造函数循环依赖?

答: 因为对象是实例化的时候,还没有实例,无法解决构造函数的循环依赖,会直接报错 。

Spring有没有解决多例下的循环依赖?

答: 多例是不存在缓存当中的,没有解决缓存依赖,如果是多例并且正在创建就会直接报错。

4.0 总结

getBean的整个过程:

1)getgetSingleton 从缓存中获取对象;

  • 从一级缓存中获取完整对象;
  • 若一级对象中没有并且是循环依赖,从二级缓存获取;
  • 若二级缓存没有并且是循环依赖,从三级缓存获取;
  • 若三级缓存不为空,从三级缓存中的函数接口中获取对象,并放入二级缓存,删除三级缓存。

2)对象实例化;

3)对象放入三级缓存

4)对象属性赋值

5)对象初始化后放入一级缓存,并删除二级缓存。

源码中的循环依赖的逻辑和手写循环依赖差不多但是个别细节缺失,这里只是让大家有个主要的思路,并不是去扣源码的细节的。若有不同意见或问题可以在评论中提出,谢谢。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

苹水相峰

你的打赏是对我最大的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值