警告
本文最后更新于 2020-11-27,文中内容可能已过时。
spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework 。
链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。
1 什么是循环依赖
在我们日常开发中,肯定存在这种情况:bean A 某个成员是 bean B,bean B 中某个属性是 bean A。那A类和B类就是相互依赖的关系,也叫循环依赖。
当然,也可以是这种情况 A -> B -> C -> D -> E -> A。这种关系也是循环依赖。
2 循环依赖在spring中的实现原理
1
2
3
4
5
6
7
8
9
@Service
public class CyclicGoodsServiceImpl implements CyclicGoodsService {
@Autowired
private CyclicOrderService cyclicOrderService ;
@Override
public CyclicOrderService getCyclicOrderService () {
return cyclicOrderService ;
}
}
2.1 源码分析
在这之前,先看一个简单的循环依赖代码案例 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Service
public class CyclicGoodsServiceImpl implements CyclicGoodsService {
@Autowired
private CyclicOrderService cyclicOrderService ;
@Override
public CyclicOrderService getCyclicOrderService () {
return cyclicOrderService ;
}
}
@Service
public class CyclicOrderServiceImpl implements CyclicOrderService {
@Autowired
private CyclicGoodsService cyclicGoodsService ;
@Override
public CyclicGoodsService getCyclicGoodsService () {
return cyclicGoodsService ;
}
}
@Slf4j
public class ApplicationContextTest {
@Test
public void testCyclicDependence (){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext ( "top.wlz922.cyclic" );
CyclicGoodsService goodsService = context . getBean ( CyclicGoodsService . class );
CyclicOrderService orderService = context . getBean ( CyclicOrderService . class );
log . debug ( goodsService . toString ());
log . debug ( orderService . toString ());
}
}
只是简单的打印一下两个Service类中属性的值,很明显是注入成功了。
以下是打印的内容:
1
2
19:34:42.334 [main] DEBUG top.wlz922.test.context.ApplicationContextTest 36 - top.wlz922.cyclic.CyclicGoodsServiceImpl@7fa98a66
19:34:42.335 [main] DEBUG top.wlz922.test.context.ApplicationContextTest 37 - top.wlz922.cyclic.CyclicOrderServiceImpl@15ff3e9e
前面的文章中已经分析过,spring中获取bean实例的方法是getBean()。在容器启动的时候,会调用这些方法,实例化单例bean实例。
直接来到doGetBean(),看以下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected < T > T doGetBean ( final String name , @Nullable final Class < T > requiredType ,
@Nullable final Object [] args , boolean typeCheckOnly ) throws BeansException {
//转换beanName,这里传入进来的beanName可能是以&开头的,这里会截掉&
final String beanName = transformedBeanName ( name );
Object bean ;
/*
TODO 这里多级缓存用于解决循环依赖问题。
注:循环依赖只能是属性见的依赖,不能是构造函数中参数的循环依赖。
从缓存(一级二级三级缓存依次获取,获取到就返回)中获取单例实例,如果获取到并且是无参构造函数,则将bean变量的值赋值。
*/
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton ( beanName );
if ( sharedInstance != null && args == null ) {
// 省略无关代码
// 如果bean不是FactoryBean类型或者beanName以&开头,则直接返回。
// 否则将bean强转为FactoryBean类型,并调用getObject()方法返回。
bean = getObjectForBeanInstance ( sharedInstance , name , beanName , null );
}
// 省略无关代码...
return ( T ) bean ;
}
}
先跳过无关代码,看关键点。从上面代码中可以看出,在doGetBean()中先调用了getSingleton(),如果这个值不为空就调用getObjectForBeanInstance(),经过一定的处理(先不要关心具体处理了什么),返回这个bean实例。
可以先分析,从接收变量的变量名sharedInstance就可以看出来,这是一个bean实例。关键点就在getSingleton()方法,这里可能会获取到一个bean实例。
下面是 getSingleton() 源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** 一级缓存 里面存储的是bean实例,在bean实例化完成、依赖注入、代理生成等流程全部完成之后,会存储到这个容器中 */
/** Cache of singleton objects: bean name to bean instance. */
private final Map < String , Object > singletonObjects = new ConcurrentHashMap <> ( 256 );
/**
* 三级缓存,在单例bean刚刚创建完成时,会将其封装成一个ObjectFactory对象,存储到这个容器中。键值是beanName。
* 从源码中可以看到,实际上是提供了一些通过BeanPostProcessor进行的扩展操作。这里不会执行,只是把这个扩展操作流程封装起来。
* 实际上,这里封装的一个函数式接口,在这里可以通过BeanPostProcessor进行一些扩展操作,其节点是bean实例化之后,
* 在真正getBean时,会触发调用。 */
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map < String , ObjectFactory <?>> singletonFactories = new HashMap <> ( 16 );
/**
* 二级缓存 从三级缓存获取后,会将bean实例存储到二级缓存,并从三级缓存中移除。这里封装了一个函数式接口的匿名实例,
* 依赖注入过程中通过getBean方法获取这个实例时,可以对其进行一些指定操作,比如说aop代理对象生成,就可能在这里触发。
*/
/** Cache of early singleton objects: bean name to bean instance. */
private final Map < String , Object > earlySingletonObjects = new HashMap <> ( 16 );
protected Object getSingleton ( String beanName , boolean allowEarlyReference ) {
/**
* 从一级缓存中取,如果有值,则返回。否则依次查找二级、三级缓存,如果最终从三级缓存中拿到值,
* 则将bean对象升级到二级缓存,并把原值从三级缓存中移除。
*/
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 ;
}
}
从源码添加的中文注释中可以看出,BeanFactory有这么三个关键成员。分别是一、二、三级缓存。
一级缓存 singletonObjects:封装了最终完成了所有处理流程的Bean。
二级缓存 earlySingletonObjects:封装了通过ObjectFactory.getObject()处理过后的对象。
三级缓存 singletonFactories:Bean刚刚创建完实例后,将Bean实例封装成ObjectFactory对象,存储到这里。
暂且记着这三个缓存的作用,来找bean被存储到三级缓存的源头。
在一个bean刚刚创建的时候,会调用到doCreateBean方法,在这个方法中真正实例化了bean,那么实例化完成之后,紧接着就会将其包装成ObjectFactory对象,存储到三级缓存。来到这块代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object doCreateBean ( final String beanName , final RootBeanDefinition mbd , final @Nullable Object [] args )
throws BeanCreationException {
// 省略无关代码...
// 创建bean实例
if ( instanceWrapper == null ) {
instanceWrapper = createBeanInstance ( beanName , mbd , args );
}
final Object bean = instanceWrapper . getWrappedInstance ();
// 省略代码:对一些注解支持的扫描、合并到BeanDefinition...
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
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实例的引用,这时候的bean是刚刚创建完成的,还没有进行属性的依赖注入、等流程处理。
addSingletonFactory ( beanName , () -> getEarlyBeanReference ( beanName , mbd , bean ));
}
}
}
从上面列出的spring源码中可以看到,当一个bean创建完实例后,会调用addSingletonFactory(),这个方法的第二个参数,传递了一个匿名对象,这个对象就是ObjectFactory类型的。
来到addSingletonFactory()源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
protected void addSingletonFactory ( String beanName , ObjectFactory <?> singletonFactory ) {
Assert . notNull ( singletonFactory , "Singleton factory must not be null" );
synchronized ( this . singletonObjects ) {
if ( ! this . singletonObjects . containsKey ( beanName )) {
// 将这个bean的匿名对象,存储到三级缓存。匿名对象中封装了一个扩展点的操作。
this . singletonFactories . put ( beanName , singletonFactory );
this . earlySingletonObjects . remove ( beanName );
this . registeredSingletons . add ( beanName );
}
}
}
}
可以看到,在bean刚刚创建完成,就把其封装到了ObjectFactory中,存储到了三级缓存singletonFactories(一个Map)。
从调用这个方法的地方(addSingletonFactory()),可以看到,这个匿名函数的内容:() -> getEarlyBeanReference(beanName, mbd, bean)
来看一下这个匿名对象具体做了什么:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
protected Object getEarlyBeanReference ( String beanName , RootBeanDefinition mbd , Object bean ) {
Object exposedObject = bean ;
// 获取早期的Bean对象的引用,这时候的Bean还没有完成依赖注入及其后面的流程。
// 在这里获取引用时,支持一些扩展操作,其扩展内容是通过 getEarlyBeanReference() 实现的。
// getEarlyBeanReference() 来自 BeanPostProcessor 的子接口 SmartInstantiationAwareBeanPostProcessor。
if ( ! mbd . isSynthetic () && hasInstantiationAwareBeanPostProcessors ()) {
for ( BeanPostProcessor bp : getBeanPostProcessors ()) {
if ( bp instanceof SmartInstantiationAwareBeanPostProcessor ) {
SmartInstantiationAwareBeanPostProcessor ibp = ( SmartInstantiationAwareBeanPostProcessor ) bp ;
exposedObject = ibp . getEarlyBeanReference ( exposedObject , beanName );
}
}
}
return exposedObject ;
}
}
从源码中可以看出:在返回早期暴露的Bean实例引用之前,会通过 BeanPostProcessor 进行一些处理。
处理内容:
摘要
获取到容器中所有已注册的BeanPostProcessor。
判断是否是其子接口SmartInstantiationAwareBeanPostProcessor类型,如果是,强转。
调用 getEarlyBeanReference() 获取Bean提前暴露对象的引用,在这里可以对Bean实例做一些扩展操作(比如生成代理对象等)。
在addSingletonFactory(),可以看到,这里只是将扩展操作封装起来,放入三级缓存,并没有调用它。
回到文章开头部分,依次从一、二、三级缓存中获取实例,在执行三级缓存获取操作时,就会调用这个方法,拿到Bean提前暴露的引用。拿到之后从三级缓存中移除,放入二级缓存。然后返回。
这也解释了为什么多个实例之间相互依赖,spring依然能够将依赖实例注入到对应成员中。
还有一个点,在哪里放入到一级缓存的?前面的文章中,有列出创建bean实例的入口,createBean方法是在一个函数式接口方法中调用的,它的上层方法是getSingleton()。
来到getSingleton()源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
public Object getSingleton ( String beanName , ObjectFactory <?> singletonFactory ) {
Assert . notNull ( beanName , "Bean name must not be null" );
synchronized ( this . singletonObjects ) {
// 省略无关代码...
//这里调用了外层传进来的匿名内部类,lambda表达式。
singletonObject = singletonFactory . getObject ();
newSingleton = true ;
// 省略无关代码...
// 加入一级缓存
if ( newSingleton ) {
addSingleton ( beanName , singletonObject );
}
}
return singletonObject ;
}
}
singletonFactory.getObject() 中调用了createBean,这里完成了bean的实例化、依赖注入、代理生成等等操作。
在createBean所有操作完成之后,最后调用了addSingleton()方法。这里把bean实例加入到了一级缓存,并从二级缓存中移除。
来到addSingleton()源码:
1
2
3
4
5
6
7
8
9
10
11
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
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容器,暂不讨论。
2.2 源码中要注意的细节
注意
构造函数中的依赖注入不可以循环依赖,多例依赖注入也不可以循环依赖。
多例情况,如果有循环依赖,会抛出异常,源码如下:
1
2
3
4
5
6
7
8
9
10
11
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
protected < T > T doGetBean ( final String name , @Nullable final Class < T > requiredType ,
@Nullable final Object [] args , boolean typeCheckOnly ) throws BeansException {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 多例不支持循环引用。多例时,如果返回指定的原型bean是否正在创建中,则抛出异常。
if ( isPrototypeCurrentlyInCreation ( beanName )) {
throw new BeanCurrentlyInCreationException ( beanName );
}
}
}
构造函数中如果有循环依赖,源码ConstructorResolver类中有这段代码,抛出异常:
1
2
3
4
5
6
try {
// 省略无关代码,如果这里有构造函数中的循环依赖,则抛出异常
} catch ( BeansException ex ) {
throw new UnsatisfiedDependencyException (
mbd . getResourceDescription (), beanName , new InjectionPoint ( methodParam ), ex );
}
2.3 流程梳理
例如有A、B两个类进行实例化,分别将对方的实例注入到自身成员中,代码如下(前文中类似案例 ):
1
2
3
4
5
6
7
8
9
10
11
@Service
public class A {
@Autowired
private B b ;
}
@Service
public class B {
@Autowired
private A a ;
}
分析上面代码的执行流程:
A 类无参构造函数实例化后, 设置三级缓存。
A 类 populateBean 进行依赖注入, 这里触发了属性 B 的 getBean 操作。
B 类无参构造函数实例化后,设置三级缓存。
B 类 populateBean 进行依赖注入,这里触发了属性 A 的 getBean 操作
A 类之前正在实例化, singletonsCurrentlyInCreation 集合中有已经有这个 A 实例了,三级缓存里面也有了,所以这时候是从三级缓存中拿到的提前暴露的 A 实例,该实例还没有进行属性 B 的依赖注入,属性 B 为空。
B 类拿到了 A 的提前暴露实例注入到属性 A 中了。
B 类实例化已经完成,B 类的实例化是由 A 类实例化中属性 B 的依赖注入触发的 getBean 操作进行的,现在 B 已经实例化,所以 A 类中属性 B 就可以完成依赖注入了,这时候 A 类 B 属性已经有值了。
B 类 A 属性指向的就是 A 类实例堆空间,所以这时候 B 类 A 属性也会有值了。