面试官:讲讲spring循环依赖问题?

前言

作为一道高频面试题,本文主要从源码的角度进行讲解。


循环依赖问题

关于 spring 循环依赖问题指的是循环引用,就是两个或两个以上的bean互相需要对方的引用,形成环状。

A依赖B,B依赖A(如下图)

A依赖B,B依赖C,C依赖A(如下图)

spring中出现循环依赖的场景有以下几种:

  • 单例属性注入(能解决)
  • 多例属性注入(不能解决)
  • 构造注入(不能解决)

至于几种循环依赖的场景,有的spring帮我们解决了,而有的并没有解决掉。那能解决的问题spring是如何解决的?不能解决的又是为什么不能解决?出现了什么问题导致不能解决?我们往下看。


单例属性注入

代码中单例属性注入的循环依赖是这样体现的:

@Component
public class TestService1 {

    @Autowired
    private TestService2 testService2;

    public void test() {
    }
}

@Component
public class TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test() {
    }
}

在上述代码中,TestService1 类标注了 @Component,会被注入到 spring 容器中,而 TestService1 中有 TestService2 的属性,在向IOC容器中注入 TestService1 的过程中还需要从IOC容器中取出 TestService2 对象,填充到 TestService1 的 bean 中,而此时,IOC容器中还没有 TestService2 bean,此时,就需要先将 TestService2 注入到 IOC 容器,但在注入 TestService2 的过程中,TestService2 中也有 TestService1 的属性,就需要从 IOC 容器中取出 TestService1 的 bean ,填充到 TestService2 bean 中,而现在 TestService1 还没有注入到 IOC 容器,又会重复上述过程,这就产生了循环依赖问题。

上述问题是最经典的循环依赖问题,但是我们在程序中这样写,并不会出现问题,而且都能够获取到这两个 bean,那无疑是 spring 帮我们解决了这个循环依赖问题,那它是怎么解决的?下面我们从源码的角度一探究竟。


spring如何解决的循环依赖问题?

在看源码前,我们要知道 bean 的创建过程中的几个步骤,理解了bean创建的步骤会对理解循环依赖问题大有帮助。

  • 实例化bean
  • 填充属性
  • 初始化bean
  • aop
  • 放入单例池(一级缓存)

以上述循环依赖的例子来说,解决循环依赖问题的步骤用一张图表示 [图片来自网络]

在这里插入图片描述

源码时序图

源码分析

这一切还要从AbstractApplicationContext 类的 refresh() 方法开始说起,refresh() 方法把 spring 容器加载的过程展现的淋漓尽致。

refresh()
@Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
    // 准备,记录容器的启动时间startupDate, 标记容器为激活,初始化上下文环境如文件路径信息,验证必填属性是否填写 
    prepareRefresh();

    // 告诉子类去刷新bean工厂,这步完成后配置文件就解析成一个个bean定义,注册到BeanFactory(但是未被初始化,仅将信息写到了beanDefination的map中)
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 
    // 设置beanFactory类加载器,添加多个beanPostProcesser
    prepareBeanFactory(beanFactory);
 
    try {
        // 允许子类上下文中对beanFactory做后期处理
        postProcessBeanFactory(beanFactory);
 
        // 调用BeanFactoryPostProcessor各个实现类的方法
        invokeBeanFactoryPostProcessors(beanFactory);
 
        // 注册 BeanPostProcessor 的实现类,注意看和 BeanFactoryPostProcessor 的区别
        // 此接口两个方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
        // 两个方法分别在 Bean 初始化之前和初始化之后得到执行。注意,到这里 Bean 还没初始化
        registerBeanPostProcessors(beanFactory);
 
        //初始化ApplicationContext的MessageSource
        initMessageSource();
 
        //初始化ApplicationContext事件广播器
        initApplicationEventMulticaster();
 
        // 初始化子类特殊bean(钩子方法)
        onRefresh();
 
        // 注册事件监听器
        registerListeners();
 
        // 初始化所有singleton bean(非lazy)
        finishBeanFactoryInitialization(beanFactory);
 
        // 广播事件,ApplicationContext初始化完成
        finishRefresh();
} catch (BeansException ex) {
....................
}

我们今天的重点是讲循环依赖,refresh() 中重中之重的方法 finishBeanFactoryInitialization(beanFactory); 我们要的答案就在这里。接着进到 finishBeanFactoryInitialization()中

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
......
	// 实例化所有剩余的 singleton bean
	beanFactory.preInstantiateSingletons();
}
preInstantiateSingletons()

ConfigurableListableBeanFactory 是个接口,我们要找到它的实现类 DefaultListableBeanFactory 的 preInstantiateSingletons() 才行。

@Override
public void preInstantiateSingletons() throws BeansException {
	......

	// 将所有 beanName 放到 list 中,此时 beanNames 中存放的是: TestService1 ,TestService2
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// 遍历 beanNames 初始化所有非lazy的 singleton bean
	for (String beanName : beanNames) {
		// 将 GenericBeanDefinition 类型的 bean 转换成 RootBeanDefinition 类型的 bean,方便后续操作
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 非抽象、单例、非懒加载(TestService1 符合条件,进入此if)
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 此bean是否实现了FactoryBean接口(TestService1 并没有实现FactoryBean,不进入此if)
			if (isFactoryBean(beanName)) {
				//  获取 bean
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					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());
					}
					// 判断是否急切的希望初始化,就获取bean
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			}
			else {
				// 如果 bean 没有实现FactoryBean接口,就获取bean(去获取 TestService1 bean)
				getBean(beanName);
			}
		}
	}
	......
}

doGetBean()

我们看看是如何获取 testService1 bean的,进入到 getBean(beanName); 随后进入到 doGetBean(),看到 do 开头的方法就说明要正儿八经的做事了。(敲黑板)

protected <T> T doGetBean(
		String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
		throws BeansException {
	// 获取解析后的规范beanName(此时beanName为:testService1)
	String beanName = transformedBeanName(name);
	Object beanInstance;

	// Eagerly check singleton cache for manually registered singletons.
	// 急切的检查缓存中是否有手动注册的单例bean(testService1 还没有注入到IOC容器中,所以单例池中没有 testService1 实例,不进入此if)
	Object sharedInstance = getSingleton(beanName);
	if (sharedInstance != null && args == null) {
		......
	}
	else {
		// 判断多例bean是否正在创建中(testService1 是单例bean,所以不进入此if)
		if (isPrototypeCurrentlyInCreation(beanName)) {
			throw new BeanCurrentlyInCreationException(beanName);
		}
		// ...... 检查此工厂中是否存在 bean 定义

		// 如果不用作类型检查,就给当前bean标记为已创建(放入到set集合)
		if (!typeCheckOnly) {
			markBeanAsCreated(beanName);
		}
		......
		try {
			......
			// 将 bean 转换为 RootBeanDefinition 类型
			RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);

			// ....... 保证当前bean依赖的bean的初始化
			
			// Create bean instance.
			if (mbd.isSingleton()) {
				// 返回创建的原始对象,如果未创建,则创建一个新对象(创建 testService1 bean)
				sharedInstance = getSingleton(beanName, () -> {
					try {
						// 真正创建 bean 实例
						return createBean(beanName, mbd, args);
					}
					catch (BeansException ex) {
						// 从三个缓存中显式移除bean,销毁bean以及bean临时引用的所有bean
						destroySingleton(beanName);
						throw ex;
					}
				});
				beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
			}
				......
			}

			else {
				......
			}
		}
		catch (BeansException ex) {
			......
		}
		finally {
			beanCreation.end();
		}
	}

	return adaptBeanInstance(name, beanInstance, requiredType);
}

可以看到此时 testService1 是个半成品 bean,因为已经完成了实例化 testService1,但是其中的属性 testService2 还未填充。


三个缓存

先来认识一下 spring 解决循环依赖问题用到的重要的三个缓存:

/** 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. */
// 三级缓存,存储用于生成半成品bean的lambda表达式
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/** Cache of early singleton objects: bean name to bean instance. */
// 二级缓存,存储已经实例化完成,但未初始化完成的半成品bean
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

我们从上述 doGetBean() 方法中遇到过从单例池中获取 bean 的方法 getSingleton(beanName),看看它的内部实现逻辑。

@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	// Quick check for existing instance without full singleton lock
	// 从一级缓存中取bean
	Object singletonObject = this.singletonObjects.get(beanName);
	// 一级缓存中没有此bean 并且 当前单例bean正在创建(spring把所有正在创建过程的bean放到set集合中,如此bean创建完成则会从此set集合移除)
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		// 如一级缓存中没有bean则从二级缓存中取
		singletonObject = this.earlySingletonObjects.get(beanName);
		// 二级缓存中没有此半成品bean并且允许创建早期单例对象引用(此值默认为true)
		if (singletonObject == null && allowEarlyReference) {
			// synchronized 锁住一级缓存的实例变量,是个对象锁
			synchronized (this.singletonObjects) {
				// 从一级缓存中获取 bean
				singletonObject = this.singletonObjects.get(beanName);
				if (singletonObject == null) {
					// 从二级缓存中获取半成品bean(已经完成实例化,但未进行属性填充和初始化)
					singletonObject = this.earlySingletonObjects.get(beanName);
					if (singletonObject == null) {
						// 从三级缓存中获取用于生成半成品bean的lambda表达式
						ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
						if (singletonFactory != null) {
							// 执行此 lambda表达式,创建半成品bean(已经完成实例化,但未进行属性填充和初始化)
							singletonObject = singletonFactory.getObject();
							// 将此半成品 bean 存储到 二级缓存中
							this.earlySingletonObjects.put(beanName, singletonObject);
							// 将生成此bean的Lambda从三级缓存中移除
							this.singletonFactories.remove(beanName);
						}
					}
				}
			}
		}
	}
	return singletonObject;
}

因为注入 testService1 bean 时,执行 getSingleton(String beanName, boolean allowEarlyReference) 方法得到的结果为null,因为此时一级缓存中没有 testService1 bean ,所以 singletonObject==null ,但是 testService1 没有在创建过程中,所以 isSingletonCurrentlyInCreation(beanName) 返回为 false,所以此时返回的 singletonObject 为 null

在 doGetBean() 中由于 getSingleton() 返回的 sharedInstance 为null,所以会走到下面的 getSingleton(String beanName, ObjectFactory<?> singletonFactory)

// Create bean instance.
if (mbd.isSingleton()) {
	// 返回创建的原始对象,如果未创建,则创建一个新对象(创建 testService1 bean)
	sharedInstance = getSingleton(beanName, () -> {
		try {
			// 真正创建 bean 实例
			return createBean(beanName, mbd, args);
		}
		catch (BeansException ex) {
			// 从三个缓存中显式移除bean,销毁bean以及bean临时引用的所有bean
			destroySingleton(beanName);
			throw ex;
		}
	});
	beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

getSingleton(String beanName, ObjectFactory<?> singletonFactory)

看看 getSingleton(String beanName, ObjectFactory<?> singletonFactory) 内部是如何实现的

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
	Assert.notNull(beanName, "Bean name must not be null");
	// 锁住实例变量,保证同步
	synchronized (this.singletonObjects) {
		// 从一级缓存中获取bean
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null) {
		
			// ....... 判断此bean是否正在销毁
			
			// 创建单例前的回调,默认实现是将当前beanName添加到存储正在创建的bean的set集合中
			beforeSingletonCreation(beanName);
			boolean newSingleton = false;
			boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
			if (recordSuppressedExceptions) {
				this.suppressedExceptions = new LinkedHashSet<>();
			}
			try {
				// singletonFactory 为传进来的 lambda, singletonFactory.getObject() 代表执行 lambda 创建完整的实例bean(其中包括实例化,填充属性)
				singletonObject = singletonFactory.getObject();
				// 创建了新的单例bean的标识
				newSingleton = true;
			}
			
			// ...... catch 异常			

			finally {
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = null;
				}
				// 创建单例bean后的回调, 默认将 beanName 从存放正在创建的bean的set集合中移除,代表当前bean创建完成
				afterSingletonCreation(beanName);
			}
			if (newSingleton) {
				// 将当前bean存入到一级缓存,并从二三级缓存中移除
				addSingleton(beanName, singletonObject);
			}
		}
		return singletonObject;
	}
}

看看 Lambda 中调用的 createBean(beanName, mbd, args) 方法做了哪些工作。

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
		throws BeanCreationException {
	.......
	try {
		// do开头的方法,实际createBean的方法
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		if (logger.isTraceEnabled()) {
			logger.trace("Finished creating instance of bean '" + beanName + "'");
		}
		return beanInstance;
	}
	// ...... catch
}

进入到 doCreateBean(beanName, mbdToUse, args);

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {
	......
	if (instanceWrapper == null) {
		// 创建实例bean,此方法执行结束代表当前bean已被实例化完成
		instanceWrapper = createBeanInstance(beanName, mbd, args);
	}
	
	// Eagerly cache singletons to be able to resolve circular references
	// even when triggered by lifecycle interfaces like BeanFactoryAware.
	// 单例bean && 允许循环依赖(默认true) && 当前bean正在创建
	// 根据条件判断是否提前暴露单例bean
	boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
			isSingletonCurrentlyInCreation(beanName));
	if (earlySingletonExposure) {
		if (logger.isTraceEnabled()) {
			logger.trace("Eagerly caching bean '" + beanName +
					"' to allow for resolving potential circular references");
		}
		// 将创建bean的lambda存入三级缓存
		addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
	}

	// Initialize the bean instance.
	Object exposedObject = bean;
	try {
		// 填充属性
		populateBean(beanName, mbd, instanceWrapper);
		// 执行后置处理器 postProcessBeforeInitialization和postProcessAfterInitialization
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
	// ...... catch
	// 是否提前暴露对象(此处为true)
	if (earlySingletonExposure) {
		// 从缓存中获取 bean 实例
		Object earlySingletonReference = getSingleton(beanName, false);
		if (earlySingletonReference != null) {
			if (exposedObject == bean) {
				exposedObject = earlySingletonReference;
			}
			else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
				......
		}
	}
	......
	return exposedObject;
}

实例化createBeanInstance()

进入到 createBeanInstance(beanName, mbd, args);

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	.......
	
	// Shortcut when re-creating the same bean...
	// 避免重复创建同一个bean
	boolean resolved = false;
	boolean autowireNecessary = false;
	if (args == null) {
		synchronized (mbd.constructorArgumentLock) {
			// 是否存在解析过的构造或者工厂方法
			if (mbd.resolvedConstructorOrFactoryMethod != null) {
				// 解析过的标识
				resolved = true;
				// 解析的构造是否有参数的标识
				autowireNecessary = mbd.constructorArgumentsResolved;
			}
		}
	}
	// 如果解析过
	if (resolved) {
		// 解析的是否是有参构造
		if (autowireNecessary) {
			// 返回需要的参数个数、类型的构造创建实例的bean包装器
			return autowireConstructor(beanName, mbd, null, null);
		}
		else {
			// 使用默认构造创建实例的bean包装器
			return instantiateBean(beanName, mbd);
		}
	}
	// Candidate constructors for autowiring?
	// 从后期处理器中确定需要的构造
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	// 构造存在 || 类型为构造函数注入 || 传入参数不为空
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
		// 获取创建bean的包装器
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// Preferred constructors for default construction?
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
		// 获取创建bean的包装器
		return autowireConstructor(beanName, mbd, ctors, null);
	}

	// No special handling: simply use no-arg constructor.
	// 使用默认构造创建实例的bean包装器
	return instantiateBean(beanName, mbd);
}

由于我们注入的 testCircleDependA 是无参构造,所以真正实例化 testCircleDependA 的方法是上面 createBeanInstance() 中的 instantiateBean(beanName, mbd);进入到 instantiateBean(beanName, mbd);

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 {
			// 进入到 instantiate 方法实例化
			beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
		}
		BeanWrapper bw = new BeanWrapperImpl(beanInstance);
		initBeanWrapper(bw);
		return bw;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
	}
}

进入到 instantiate 方法实例化

@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
	// Don't override the class with CGLIB if no overrides.
	if (!bd.hasMethodOverrides()) {
		Constructor<?> constructorToUse;
		synchronized (bd.constructorArgumentLock) {
			constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
			if (constructorToUse == null) {
				// 获取当前实例化的bean的class
				final Class<?> clazz = bd.getBeanClass();
				if (clazz.isInterface()) {
					throw new BeanInstantiationException(clazz, "Specified class is an interface");
				}
				try {
					if (System.getSecurityManager() != null) {
						constructorToUse = AccessController.doPrivileged(
								(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
					}
					else {
						// 关键的一步,通过反射获取到 testService1 的无参构造
						constructorToUse = clazz.getDeclaredConstructor();
					}
					bd.resolvedConstructorOrFactoryMethod = constructorToUse;
				}
				catch (Throwable ex) {
					throw new BeanInstantiationException(clazz, "No default constructor found", ex);
				}
			}
		}
		// 拿着无参构造去实例化 testService1 
		return BeanUtils.instantiateClass(constructorToUse);
	}
	else {
		// Must generate CGLIB subclass.
		return instantiateWithMethodInjection(bd, beanName, owner);
	}
}

进入到 instantiateWithMethodInjection(bd, beanName, owner);

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
	Assert.notNull(ctor, "Constructor must not be null");
	try {
		// 反射 取消java语言的安全检查
		ReflectionUtils.makeAccessible(ctor);
		if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
			return KotlinDelegate.instantiateClass(ctor, args);
		}
		else {
			// 获取 testCircleDependA 无参构造的参数类型(因为是无参构造,所以 parameterTypes 为空数组)
			Class<?>[] parameterTypes = ctor.getParameterTypes();
			Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
			Object[] argsWithDefaultValues = new Object[args.length];
			for (int i = 0 ; i < args.length; i++) {
				if (args[i] == null) {
					Class<?> parameterType = parameterTypes[i];
					argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
				}
				else {
					argsWithDefaultValues[i] = args[i];
				}
			}
			// 根据无参构造的参数值去实例化 testService1 (此刻,直接去执行 testService1 的无参构造获得 testService1 bean)
			return ctor.newInstance(argsWithDefaultValues);
		}
	}
	// ....... 一些 catch
}

此时,testService1 才是真正完成实例化。简单总结一下,利用反射获取 testService1 的 class,再根据 class 和我们注入 IOC 容器的方式拿到具体哪一个构造,拿到构造执行去执行指定的构造函数,实例化完成。到现在为止,我们只是实例化完了 testService1 bean 还没有对其进行属性填充。上述方法执行完 return 回 doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) 方法,我们走到 populateBean(beanName, mbd, instanceWrapper); 看看是如何进行属性填充的。


填充属性-populateBean()

我们刚刚实例化完的 bean 是 testService1 ,所以,下面要给 testService1 填充属性 testServce2

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	.......
	
	// 获取 bean 的属性值(此时 pvs 为 null)
	PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

	// 获取自动装配标识(此时 resolvedAutowireMode 为0,代表没有外部定义的自动装配的常量,将应用 BeanFactoryAware 等和注解驱动的注入)
	int resolvedAutowireMode = mbd.getResolvedAutowireMode();
	// 根据bean名称装配 || 根据bean类型装配(resolvedAutowireMode 为0,所以不进入此if)
	if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
		......
	}
	......
	// 后置处理器标识
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	// 依赖检查标识
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			// 获取 testCircleDependA 属性值
			pvs = mbd.getPropertyValues();
		}
		// 变量实例化bean的后置处理器,就是在这进行的属性填充
		for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
			PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
			if (pvsToUse == null) {
				if (filteredPds == null) {
					filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
				}
				pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					return;
				}
			}
			pvs = pvsToUse;
		}
	}
	// 依赖检查(needsDepCheck为false)
	if (needsDepCheck) {
		if (filteredPds == null) {
			filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
		}
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
	if (pvs != null) {
		// 注入属性方法
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
}

我们进入到 bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);

@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
	// 获取注入的bean的元数据
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
		// 注入属性
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

我们看下获取到的 metadata 中都哪些信息?
在这里插入图片描述

可以清楚的看到需要注入的目标类是 TestService1,而注入的元素是:TestService2

再进入到 metadata.inject(bean, beanName, pvs);

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
	// 获取需要填充的元素
	Collection<InjectedElement> checkedElements = this.checkedElements;
	Collection<InjectedElement> elementsToIterate =
			(checkedElements != null ? checkedElements : this.injectedElements);
	if (!elementsToIterate.isEmpty()) {
		for (InjectedElement element : elementsToIterate) {
			// 填充属性
			element.inject(target, beanName, pvs);
		}
	}
}

再进入 element.inject(target, beanName, pvs);方法

@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
		Field field = (Field) this.member;
		Object value;
		if (this.cached) {
			try {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Unexpected removal of target bean for cached argument -> re-resolve
				value = resolveFieldValue(field, bean, beanName);
			}
		}
		else {
			value = resolveFieldValue(field, bean, beanName);
		}
		if (value != null) {
			// 反射!!!
			ReflectionUtils.makeAccessible(field);
			field.set(bean, value);
		}
	}

看到这,就恍然大明白了,依然是使用反射将属性注入。

一直跟到底层,会发现最后实际填充属性的是行代码,Unsafe 的 native 方法

unsafe.putObject(var1, this.fieldOffset, var2);

初始化initializeBean()

此时,已经完成 testService1的属性填充。populateBean() 执行结束回到 doCreateBean() ,进入到 exposedObject = initializeBean(beanName, exposedObject, mbd); 方法初始化 testService2 bean

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
	......

	Object wrappedBean = bean;
	if (mbd == null || !mbd.isSynthetic()) {
		// 初始化bean前执行bean的后置处理器
		wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
	}

	try {
		// 调用初始化bean方法
		invokeInitMethods(beanName, wrappedBean, mbd);
	}
	catch (Throwable ex) {
		throw new BeanCreationException(
				(mbd != null ? mbd.getResourceDescription() : null),
				beanName, "Invocation of init method failed", ex);
	}
	if (mbd == null || !mbd.isSynthetic()) {
		// 初始化bean后执行 bean 的后置处理器
		wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	}

	return wrappedBean;
}

我们进入到真正初始化bean的方法invokeInitMethods(beanName, wrappedBean, mbd);

protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {
	// 判断当前bean是否正在初始化(false)
	boolean isInitializingBean = (bean instanceof InitializingBean);
	// 当前bean正在初始化 && (mbd为null || 不是外部管理的初始化方法)(不进入此if)
	if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
		......
	}

	if (mbd != null && bean.getClass() != NullBean.class) {
		// 获取初始化方法名称(此处为null)
		String initMethodName = mbd.getInitMethodName();
		// 不进入此if
		if (StringUtils.hasLength(initMethodName) &&
				!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
				!mbd.isExternallyManagedInitMethod(initMethodName)) {
			invokeCustomInitMethod(beanName, bean, mbd);
		}
	}
}

上述初始化bean的方法 invokeInitMethods() 并没有做什么操作,执行此方法时,bean 的属性都已经填充完成,此方法的意义就是检查bean是否自定义了初始化方法,如果定义了,调用回调。由于我们没有自定义初始化方法,所以在此方法中并没有做什么有实际意义的工作。


此方法执行结束,继续回到 getSingleton(beanName,singletonFactory)方法,发现创建完整的bean结束后,代码中还做了两个操作。分别是:

  • 将当前beanName从正在创建的set集合中移除
  • 当前bean放到单例池中(一级缓存)
// 创建单例bean后的回调, 默认将 beanName 从存放正在创建的bean的set集合中移除,代表当前bean创建完成
afterSingletonCreation(beanName); 
// 将当前bean存入单例池(一级缓存),并从二三级缓存中移除
addSingleton(beanName, singletonObject);

其实以上整个过程调试完,testService1 和 testService2 都会被注入到IOC容器,并且互相注入成功。那 我们知道 testService1 bean 中的 testService2 属性是在 populateBean() 方法中填充的。那

到此为止向容器中注入一个完整的单例bean就完成了。看源码的过程中,可以对照时序图来调试。

多例属性注入

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TestService1 {

    @Autowired
    private TestService2 testService2;

    public void test() {
    }
}

@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class TestService2 {

    @Autowired
    private TestService1 testService1;

    public void test() {
    }
}

这种情况,程序可以启动成功,为什么不报错呢?

因为在 preInstantiateSingletons() 方法中有如下判断,只有满足这三个条件(非抽象、单例、非懒加载)才会被提前初始化。所以,程序启动时根本没有注入 那两个类,自然不会报异常。

if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {}

如何让它提前初始化?

我们在添加一个 TestService3 类

@Component
public class TestService3 {

    @Autowired
    private TestService1 testService1;
}

看看程序启动报的错误信息
在这里插入图片描述
多例的属性注入 spring 是无法解决的,因为在每次注入都会新建一个bean,在实例化 TestService1 过程中填充属性 TestService2 时,由于不是单例的,不能将其放到单例池中,每此注入都要新建,而实例化 TestService2 过程中填充属性 TestService1 时,也要实例化 testSerivce1 bean,成了死循环,哪个bean都无法注入成功。正是因为无法提前暴露 bean(半成品bean)才导致多例属性注入循环依赖问题没有得到解决。


构造注入

public class TestService1 {

    private TestService2 testService2;

    public TestService1(TestService2 testService2) {
        this.testService2 = testService2;
    }
}

public class TestService2 {

    private TestService1 testService1;

    public TestService2(TestService1 testService1) {
        this.testService1 = testService1;
    }
}

spring 无法解决构造注入的循环依赖问题,因为在实例化 testService1 的时候需要注入 testService2 属性,而注入就需要实例化 testService2 ,而在实例化 testService2 时又要注入 testService1。导致 testService1 和 testService2 都无法实例化完成。


常见问题

能不能只用一级缓存和二级缓存解决循环依赖问题?

一级缓存(单例池)中要存放创建完成的完整的 bean,二级缓存中存放实例化完成(但未初始化,半成品)的 bean,那为什么还要三级缓存呢?三级缓存中存的是提前曝光的对象,不是将 bean,而是将 Bean 包装成 ObjectFactory 存入,是个 lambda 表达式。

如果创建的bean有aop,就要生成对应的代理对象,aop完成后会将代理对象放到一级缓存中(单例池),当其他对象需要注入当前 bean 时,注入的也应该是单例池中的代理对象(非原始对象)。如果没有循环依赖问题时,spring 会在初始化bean后进行aop,也就是生成代理对象。而当出现循环依赖问题,因为要保证注入到其他 bean 中的对象和单例池中的对象是一个对象。所以,当出现循环依赖问题并且属性需要aop时,创建 bean 的步骤是这样的:

  • 0 实例化 testServiceA 前将 testServiceA beanName 存入 set 集合中
  • 1 实例化 testServiceA -> 将 testServiceA 原始对象包装成 ObjectFactory 对象存到 三级缓存中(提前曝光)
  • 2 填充 testServiceB 属性 -> 从单例池中找,不存在 -> 创建 testServiceB bean
  • 2.1 实例化 testServiceB -> 将 testServiceB 原始对象包装成 ObjectFactory 对象存到 三级缓存中(提前曝光)
  • 2.2 填充 testServiceA 属性 -> 从单例池中找,不存在 -> 判断 testServiceA 是否出现了循环依赖(判断set集合中是否存在 testServiceA) -> 从二级缓存中找 bean(不存在)-> 从三级缓中取 bean 的 ObjectFactory 对象 -> AOP -> 生成 testServiceA 代理对象 -> 将代理对象存入二级缓存中,从三级缓存中移除,此时二级缓存中存放的是实例化完成,但未填充属性的半成品 bean
  • 2.4 初始化
  • 2.5 存入单例池
  • 3 AOP
  • 4 初始化
  • 5 从二级缓存中取 testServiceA 存入单例池(一级缓存)
  • 6 创建 bean 结束后将 testServiceA beanName 从 set 集合中移除

为什么 2.2 中还需要将 testServiceA 存到缓存中呢?生成完代理对象后直接将bean赋给 testServiceB 不就好了,之所以存到缓存中是因为如果出现了多个bean循环依赖的问题时,多个 bean 如果都需要注入 testServiceA 对象,那多个bean中注入的一定要是同一个 testServiceA,所以在生成完代理对象后把代理对象存到缓存中就发挥作用了,其他 bean 可以直接从二级缓存中取即可,确保多个bean注入的 testServiceA 是同一个代理对象。所以,二级缓存存在的意义是保证单例模式下生成的一个bean 的代理对象是单例的。

三级缓存存在的意义是为了在实例化完成 bean 后就提前曝光 bean 的 ObjectFactory 对象,当当前 bean 被注入到其他 bean 时,取出 ObjectFactory 对象生成代理对象,并将生成的代理对象存入二级缓存,同时从三级缓存中移除。

为什么二三级缓存不用 ConcurrentHashmap ?

一级缓存用了 ConcurrentHashMap 来解决线程安全问题,为什么 二三级缓存使用的是 HashMap ?

因为操作二三级缓存总是同时出现,当把 bean 存入二级缓存的同时一定要将其从三级缓存中移除,为了保证多个bean 注入的是一个代理对象。源码实现中操作二三级缓存时使用了 synchronized 同步机制,来保证线程同步。因为操作两个缓存是两个步骤,不是原子性的操作,所以 使用 synchronized 来保证线程安全。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值