多图剖析|Spring的循环依赖竟如此复杂
Spring的循环依赖文章目录Spring的循环依赖spring4和5的AOP区别什么是循环依赖Spring容器Spring的三级缓存Spring循环依赖Bean注入IOC全流程1. 创建CircleRefA2. 创建CircleRefB3. CircleRefB获取CircleRefA对象4. CircleRefB注入CircleRefA对象5. CircleRefA注入CircleRefB被A
Spring的循环依赖
文章目录
spring4和5的AOP区别
spring4的执行顺序:
对应springboot1.x
@Before(前置通知)=》@After(后置通知)=》@AfterReturning(正常返回)
@Before(前置通知)=》@After(后置通知)=》@AfterThrowing(方法异常)
spring5的执行顺序:
对应springboot2.x
@Before(前置通知)=》@AfterReturning(正常返回)=》@After(后置通知)
@Before(前置通知)=》@AfterThrowing(方法异常)=》@After(后置通知)
什么是循环依赖
多个Bean之间相互依赖,形成一个闭环。
使用构造函数注入bean时若存在循环引用将会报错,若使用set()注入bean时存在循环引用不会报错;
Spring容器
默认的单例(Singleton)的场景是支持循环依赖的不会报错,但原型(Prototype)的场景是不支持循环依赖的,会报错;
-
当两个互相引用的bean都是单例的或者其中一个是单例的则可正常创建两个bean对象;其是通过三级缓存模型解决的;
// 控制台专门输出A,B创建成功 @Component public class CircleRefA { @Autowired private CircleRefB circleRefB; @PostConstruct public void init() { System.out.println("CircleRefA 创建成功"); } } @Component public class CircleRefB { @Autowired private CircleRefA circleRefA; @PostConstruct public void init() { System.out.println("CircleRefB 创建成功"); } }
-
若两个都为原型模式,则报错
// 若是原型模式 @Component @Scope("prototype") public class CircleRefA { @Autowired private CircleRefB circleRefB; @PostConstruct public void init() { System.out.println("CircleRefA 创建成功"); } } @Component @Scope("prototype") public class CircleRefB { @Autowired private CircleRefA circleRefA; @PostConstruct public void init() { System.out.println("CircleRefB 创建成功"); } }
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'circleRefA': Unsatisfied dependency expressed through field 'circleRefB'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'circleRefB': Unsatisfied dependency expressed through field 'circleRefA'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circleRefA': Requested bean is currently in creation: Is there an unresolvable circular reference?
Spring的三级缓存
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 一级缓存
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 三级缓存
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 二级缓存
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
}
Spring中IOC含有一个DefaultSingletonBeanRegistry.class,其中就有三个map被称为bean创建时的三级缓存;
只有单例的bean会通过三级缓存模型提前存放解决循环依赖的问题,而非单例的bean,每次从容器中获取都是一个新的对象,都会重新创建,所以非单例的bean是没有缓存的,不会将其放入三级缓存模型中;
- 第一级缓存(单例池)singletonObjects:存放已经经历了完整声明周期的bean对象;
- 第二级缓存,earlySingletonObjects:存放早期暴露出来的bean对象,Bean的生命周期未结束(属性还未填充完);
- 第三级缓存,singletonFactories:存放可以生成Bean的工厂;
Spring循环依赖Bean注入IOC全流程
我们的场景和上述场景一样两个单例Bean循环依赖,CircleRefA
,CircleRefB
;
Spring扫描的顺序是先扫描CircleRefA
再扫描CircleRefB
;
整体流程
- CircleRefA创建对象,并放入三级缓存中;
- 欲将CircleRefB注入进CircleRefA中;
- 创建CircleRefB对象,并放入三级缓存中;
- 欲将CircleRefA注入进CircleRefB中;
- 从三级缓存中获取CircleRefA的工厂对象,并由工厂生成CircleRefA对象,放入二级缓存中,移除三级缓存;
- 将CircleRefA注入进CircleRefB中;
- CircleRefB完成bean创建,移除三级缓存,加入一级缓存;
- 将CircleRefB注入进CircleRefA中;
- CircleRefA完成bean创建,移除二级缓存,加入一级缓存;
@Component
public class CircleRefA {
@Autowired
private CircleRefB circleRefB;
public CircleRefA() {
System.out.println("CircleRefA new成功");
}
@PostConstruct
public void init() {
System.out.println("CircleRefA Bean创建成功");
}
}
@Component
public class CircleRefB {
@Autowired
private CircleRefA circleRefA;
public CircleRefB() {
System.out.println("CircleRefB new成功");
}
@PostConstruct
public void init() {
System.out.println("CircleRefB bean创建成功");
}
}
1. 创建CircleRefA
getSingleton(beanName,allowEarlyReference=true)
如上图所示,首先我们根据CircleRefA的db去DefaultSingletonBeanRegistry中获取是否有Bean对象;
这里由于刚开始准备注入,因此三级缓存都没有,返回null;
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存找
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
// 一级缓存未找到去二级缓存找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) { // DDL加锁
// 加锁后再去一级缓存找,怕并发已创建
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 一级缓存未找到去二级缓存找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
// 二级缓存未找到就去三级缓存找
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
// 三级缓存找到了,通过工厂创建对象放入二级缓存并删除三级缓存
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
// 三个缓存都没有返回NULL,否则返回对象
return singletonObject;
}
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
由于未在三级缓存中找到bean对象,doGetBean()这次会再次调用getSingleton(),不过这是个重载方法,这次传入一个创建CircleRefA的工厂;DefaultSingletonBeanRegistry首先再去一级缓存中判断是否已创建CircleRefA,然后再去执行工厂去创建bean;即调用createBean()方法;
// doGetBean()
// 参数1是beanName,参数2是创建该bean的工厂
sharedInstance = this.getSingleton(beanName, () -> {
try {
// 工厂的实际创建Bean方法
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
// DefaultSingletonBeanRegistry
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException;
}
try {
// 调用传入的工厂
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException var16) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw var16;
}
} catch (BeanCreationException var17) {
throw ex;
} finally {
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
// 创建好了加入一级缓存中[后续用的]
this.addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
AbstractAutowireCapableBeanFactory.doCreateBean()
bean的工厂呢,就是在这里创建Bean对象;
-
通过createBeanInstance()方法,先把对象new出来,这里使用构造器创建对象
BeanUtils.instantiateClass(constructorToUse, new Object[0])
-
addSingletonFactory()方法,将该对象加入到三级缓存中;
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized(this.singletonObjects) { // 判断一级缓存不存在 if (!this.singletonObjects.containsKey(beanName)) { // 放入三级缓存 this.singletonFactories.put(beanName, singletonFactory); // 移除二级缓存(空操作) this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
-
调用populateBean(),注入CircleRefA的属性;
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
// 调用构造函数new出来
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 加入三级缓存
boolean earlySingletonExposure = mbd.isSingleton() && this.allowCircularReferences && this.isSingletonCurrentlyInCreation(beanName);
if (earlySingletonExposure) {
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
Object exposedObject = bean;
try {
// 构造该对象成为一个bean
this.populateBean(beanName, mbd, instanceWrapper);
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
throw new BeanCreationException;
}
}
AbstractAutowireCapableBeanFactory.populateBean()
这里this.getBeanPostProcessorCache().instantiationAware()总共有4个InstantiationAwareBeanPostProcessor
处理器;
注入CircleRefB是通过最后一个`AutowiredAnnotationBeanPostProcessor处理器去注入的;
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
for(Iterator var9 = this.getBeanPostProcessorCache().instantiationAware.iterator(); var9.hasNext(); pvs = pvsToUse) {
InstantiationAwareBeanPostProcessor bp =(InstantiationAwareBeanPostProcessor)var9.next();
// `AutowiredAnnotationBeanPostProcessor进行处理
pvsToUse = bp.postProcessProperties((PropertyValues)pvs,bw.getWrappedInstance(), beanName);
}
AutowiredAnnotationBeanPostProcessor.postProcessProperties()
处理器内部主要是获取CirleRefA内部要注入的属性,然后通过构建CirleRefA的元方法,循环将其内部属性进行注入到CircleRefA的内部;
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
return pvs;
} catch (BeanCreationException var6) {
throw var6;
} catch (Throwable var7) {
throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);
}
}
// InjectionMetadata.inject()
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectionMetadata.InjectedElement> checkedElements = this.checkedElements;
Collection<InjectionMetadata.InjectedElement> elementsToIterate = checkedElements != null ? checkedElements : this.injectedElements;
if (!((Collection)elementsToIterate).isEmpty()) {
Iterator var6 = ((Collection)elementsToIterate).iterator();
while(var6.hasNext()) {
InjectionMetadata.InjectedElement element = (InjectionMetadata.InjectedElement)var6.next();
// 属性循环注入 还会调AutowiredAnnotationBeanPostProcessor.inject()
element.inject(target, beanName, pvs);
}
}
}
// AutowiredAnnotationBeanPostProcessor.inject()
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field)this.member;
// 创建属性对象
Object value = this.resolveFieldValue(field, bean, beanName);
// 属性注入到对象中
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
// 调用resolveFieldValue()
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet(1);
Assert.state(AutowiredAnnotationBeanPostProcessor.this.beanFactory != null, "No BeanFactory available");
TypeConverter typeConverter = AutowiredAnnotationBeanPostProcessor.this.beanFactory.getTypeConverter();
Object value;
try {
// 创建属性对象
value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException var12) {
throw new UnsatisfiedDependencyException((String)null, beanName, new InjectionPoint(field), var12);
}
}
DependencyDescriptor.resolveCandidate()
resolveDependency() 方法最终会调用到这块,这里又走到了getBean()上,就是紫色的线,至此就轮到CircleRefB的创建;
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
// 创建getBean()
return beanFactory.getBean(beanName);
}
2. 创建CircleRefB
此时,CircleRefA虽然new成对象,但只放在三级缓存中,然后目前准备将CircleRefB注入到CircleRefA中。因此现在根据紫色的线,走到了getBean(CircleRefB);
这时IOC中也没有CircleRefB,因此,创建CircleRefB的过程和CircleRefA的流程是一模一样;
不过,当CircleRefB要注入CircleRefA时就不一样了;接着,就是紫色的线,CircleRefB准备要注入CircleRefA了
beanFactory.getBean(CircleRefA)
;
3. CircleRefB获取CircleRefA对象
此时,CircleRefB虽然new成对象,放入三级缓存中,然后目前准备将CircleRefA注入到CircleRefB中。因此现在根据紫色的线,走到了getBean(CircleRefA);
doGetBean(CircleRefA)
由于三级缓存中有CircleRefA,因此三级缓存中取出CircleRefA的工厂,通过工厂create出CircleRefA对象(还是之前创建的CircleRefA),然后将其加入二级缓存,删除三级缓存并返回;
// 获取CircleRefA对象
protected <T> T doGetBean(String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
String beanName = this.transformedBeanName(name);
// 从缓存中取CircleRefA对象
Object sharedInstance = this.getSingleton(beanName);
Object beanInstance;
if (sharedInstance != null && args == null) {
beanInstance = this.getObjectForBeanInstance(sharedInstance, name, beanName, (RootBeanDefinition)null);
}
return this.adaptBeanInstance(name, beanInstance, requiredType);
}
此时,CircleRefB要注入的CircleRefA已经从三级缓存中返回,因此回到AutowiredAnnotationBeanPostProcessor.inject()
4. CircleRefB注入CircleRefA对象
目前回退到inject()方法,获取到CircleRefA对象了,准备将其注入进CircleRefB中;图中紫色区域,开始回退;
AutowiredAnnotationBeanPostProcessor.inject()
获取到后将CircleRefA注入进CircleRefB里。
// AutowiredAnnotationBeanPostProcessor.inject()
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field)this.member;
// 创建属性对象 此时已获取到CircleRefA
Object value = this.resolveFieldValue(field, bean, beanName);
// CircleRefA注入到CircleRefB中
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
注入完成,CircleRefB中的circleRefA已经有对象了(但目前CircleRefA中的CircleRefB还是null);因此回退到DefaultSingletonBeanRegistry.getSingleton()方法;
DefaultSingletonBeanRegistry. getSingleton(String beanName, ObjectFactory<?> singletonFactory)
目前 singletonObject = singletonFactory.getObject()已经将CircleRefB的Bean对象构建完成,此时通过addSingleton()将CircleRefB加入一级缓存中,至此Bean对象已经注入进了IOC中;
// DefaultSingletonBeanRegistry
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException;
}
try {
// 调用传入的工厂
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (IllegalStateException var16) {
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw var16;
}
} catch (BeanCreationException var17) {
throw ex;
} finally {
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
// 创建好了加入一级缓存中[后续用的]
this.addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
DefaultSingletonBeanRegistry.addSingleton()
目前将CircleRefB的bean对象加入一级缓存,并删除二,三级缓存;
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);
}
}
5. CircleRefA注入CircleRefB
这里的图和CircleRefB注入CircleRefA的图是一样的,目前CircleRefB已经是一个bean对象了,因此,CircleRefA将CircleRefB注入进去,就是图中紫色的区域,然后开始回退;
之后注入后也回退到DefaultSingletonBeanRegistry.getSingleton()方法;
DefaultSingletonBeanRegistry. getSingleton(String beanName, ObjectFactory<?> singletonFactory)
这时singletonObject = singletonFactory.getObject();已经将CircleRefA对象创建好了,通过addSingleton()方法将CircleRefA注入进IOC容器中;
// DefaultSingletonBeanRegistry
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
synchronized(this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException;
}
try {
// 调用传入的工厂
singletonObject = singletonFactory.getObject();
newSingleton = true;
} catch (Exception var16) {
// doException
} finally {
this.afterSingletonCreation(beanName);
}
if (newSingleton) {
// 创建好了加入一级缓存中[后续用的]
this.addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
DefaultSingletonBeanRegistry.addSingleton()
目前将CircleRefA的bean对象加入一级缓存,并删除二,三级缓存;
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);
}
}
至此,CircleRefA和CircleRefB已经注入到IOC容器了。
被AOP代理类循环依赖的全过程
强调下,大体流程和上面的图一致,就是底下有细微差距;
情况1:先扫描被代理类
背景:People.class被AopComponent代理,先于ZBird.class扫描
@Aspect
@Component
public class AopComponent {
@Pointcut("execution(* com.test.bean.People.*(..))")
public void methodPointcut() {
}
@Around("methodPointcut()")
public void init(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入AOP");
pjp.proceed();
System.out.println("离开AOP");
}
}
// 被代理的类People
@Component
public class People {
@Autowired
private ZBird ZBird;
public void speak() {
System.out.println("hello, I am people");
}
}
// 未被代理类ZBird
@Component
public class ZBird {
@Autowired
private People people;
public void speak() {
System.out.println("hello, I am Bird");
}
}
-
创建People类对象,放入三级缓存中;
-
注入People类中的属性Zbird;
-
创建Zbird类对象,放入三级缓存中;
-
注入Zbird类中的属性People;
-
从三级缓存中取出People的工厂,工厂创建的是代理对象People并放入二级缓存中;
由图可得,ZBird取三级缓存中的时候,实际上是返回了AOP创建的代理对象,并将代理对象放入了二级缓存中;其中这个创建代理对象的函数,每次调用这个工厂都会返回一个新的代理对象;
其中,AbstractAutoProxyCreator.class中有一个earlyProxyRefrences字段,他类似一个缓存,避免重复通过工厂创建代理对象;以下是循环引用的举例说明:
当AOP代理的类先扫描时,会通过
getEarlyBeanReference()
创建代理对象,后面initializeBean()
时,再次调用postProcessAfterInitialization()
由于有缓存,不会再创建对应代理类; 当AOP代理的类后被扫描时,会直接由
initializeBean()
调用postProcessAfterInitialization()
创建代理对象; -
将代理对象People注入进Zbird中;
-
Zbird移除三级缓存,放入一级缓存;
-
People类中注入Zbird;
-
initializeBean(People类)
后再次getSingleton()
将二级缓存的People代理返回;从图中紫色部分可以看到,当people类完成Bean生命周期的时候,people对象注入了ZBird,ZBird中注入的是代理People对象;
红色部分是,spring又从工厂中将people的二级缓存取出,这里是代理对象,因此返回并注入进一级缓存的是代理对象People;
这里出现了个问题,最终从IOC中取People后,无法得到被注入的对象ZBird,因为代理对象这里是null;
-
将代理对象People放入一级缓存;
情况2:后扫描被代理类
@Aspect
@Component
public class AopComponent {
@Pointcut("execution(* com.test.bean.People.*(..))")
public void methodPointcut() {
}
@Around("methodPointcut()")
public void init(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("进入AOP");
pjp.proceed();
System.out.println("离开AOP");
}
}
// 被代理的类People
@Component
public class People {
@Autowired
private Bird bird;
public void speak() {
System.out.println("hello, I am people");
}
}
// 未被代理类Bird
@Component
public class Bird {
@Autowired
private People people;
public void speak() {
System.out.println("hello, I am Bird");
}
}
-
创建Bird对象,并放入三级缓存中;
-
欲将People对象注入进Bird中;
-
创建People对象,并放入三级缓存中;
-
欲将Bird对象注入进People中;
-
从三级缓存中取出Bird对象,并放入二级缓存中;
-
将Bird对象注入进People中;
-
调用
initializeBean(People)
返回代理对象; -
由于二级缓存没有People对象,因此直接将代理对象People返回并注入进一级缓存中;
-
People代理对象注入进Bird;
-
Bird初始化后,移除二级缓存,放入一级缓存;
Spring Bean无代理是加入IOC容器流程
- 创建Bean对象,并加入三级缓存;
- 注入Bean中的属性字段;
- Bean完成initBean();
- 将Bean加入一级缓存并移除三级缓存;
Spring Bean被AOP代理是加入IOC容器流程
- 创建Bean对象,并加入三级缓存;
- 注入Bean中的属性字段;
- Bean完成initBean(),并由AOP处理器返回代理对象Bean;
- 将代理对象Bean加入一级缓存并移除三级缓存;
更多推荐
所有评论(0)