文章目录
前言
作为一道高频面试题,本文主要从源码的角度进行讲解。
循环依赖问题
关于 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 来保证线程安全。