Spring循环依赖
什么是Spring的循环依赖?循环依赖会存在哪些问题?
示例:AService依赖BService; BService依赖AService
@Service public class AService {//@Autowiredpublic BService bService; }
@Service public class BService {@Autowiredpublic AService aService; }
上面演示的例子就是循环注入
如果改为多例的化,运行时就会报错,循环引用异常,找不到对象
@Scope("prototype")
Spring中的循环依赖问题在单例的情况下,Spring是已经帮我们解决好了,多例没有解决循环依赖问题。
为啥,多例的情况下 Spring没有去解决循环依赖问题?
因为在多例的情况下,设置的多例的对象没有明确哪一个,就会产生循环依赖问题。
Spring多例我们要:如何解决循环依赖问题?
我们可以自己去:明确指定引用那个对象
@Service @Scope("prototype") public class AService {// @Autowiredpublic BService bService;// 为什么Aservice在创建的时候 为什么Bservice比ASERVICE 先创建public AService() {System.out.println("AService被Java的反射技术创建");}public void setbService(BService bService) {this.bService = bService;}}
@Service @Scope("prototype") public class BService {// @Autowiredpublic AService aService;public void setaService(AService aService) {this.aService = aService;} }
public class SpringApp {public static void main(String[] args) { // 1. ioc容器在创建的时候所有的单例对象是不是会被创建AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class); // // 对例子情况 当你在调用的时候才获取AService aSerivce = applicationContext.getBean("AService", AService.class);BService bSerivce = applicationContext.getBean("BService", BService.class);aSerivce.setbService(bSerivce);bSerivce.setaService(aSerivce);// 循环引用异常 找不到对象/*** 思考问题? 如果我们的项目对象必须要是多例? 而且必须要循环引用 明确的指定引用那个对象*/String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();for (int i = 0; i < beanDefinitionNames.length; i++) {System.out.println(beanDefinitionNames[i]);}
SpringBean循环依赖三级缓存概念
思考问题:单例对象在什么时候创建?
在IOC容器被创建的时候创建
多例的情况下,是在getbean()调用的情况下创建。多例对象每次用完就会去销毁掉。
SpringBean Aservice对象被创建流程步骤源码分析
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory);
// Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons();
public Object getBean(String name) throws BeansException {return this.doGetBean(name, (Class)null, (Object[])null, false); }
public Object getSingleton(String beanName) {return this.getSingleton(beanName, true); }
获取缓存对象:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {Object singletonObject = this.singletonObjects.get(beanName); //根据BeanName去集合中查,查到就返回这个对象,【】【】【】一级缓存对象集合【】【】【】缓存完整对象【】【】完整对象表示对象已经创建完了,并且对象属性已经赋值了。if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {Map var4 = this.singletonObjects;synchronized(this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName); //查询二级缓存中是否有缓存对象if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName); //查询三级缓存,三级缓存中有的化,将三级缓存中的数据放入二级缓存中if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject; }
一级缓存没有找到,就去找二级缓存中找
singletonObject == null && this.isSingletonCurrentlyInCreation(beanName) //一级缓存没有,并且singletonsCurrentlyInCreation判断是否之前标记为该对象开始创建
if (isPrototypeCurrentlyInCreation(beanName)) { //我们对象是单例的,所有不进入throw new BeanCurrentlyInCreationException(beanName); }
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "Bean name must not be null");synchronized (this.singletonObjects) {Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {if (this.singletonsCurrentlyInDestruction) {throw new BeanCreationNotAllowedException(beanName,"Singleton bean creation not allowed while singletons of this factory are in destruction " +"(Do not request a bean from a BeanFactory in a destroy method implementation!)");}if (logger.isDebugEnabled()) {logger.debug("Creating shared instance of singleton bean '" + beanName + "'");}beforeSingletonCreation(beanName);boolean newSingleton = false;boolean recordSuppressedExceptions = (this.suppressedExceptions == null);if (recordSuppressedExceptions) {this.suppressedExceptions = new LinkedHashSet<>();}try {singletonObject = singletonFactory.getObject();newSingleton = true;}catch (IllegalStateException ex) {// Has the singleton object implicitly appeared in the meantime ->// if yes, proceed with it since the exception indicates that state.singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {throw ex;}}catch (BeanCreationException ex) {if (recordSuppressedExceptions) {for (Exception suppressedException : this.suppressedExceptions) {ex.addRelatedCause(suppressedException);}}throw ex;}finally {if (recordSuppressedExceptions) {this.suppressedExceptions = null;}afterSingletonCreation(beanName);}if (newSingleton) {addSingleton(beanName, singletonObject);}}return singletonObject;} }
protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);} }
标识为该对象开始创建
最终调用
正真去创建我们的Bean对象:
既然要创建对象,先反射走无参构造函数,对象先实例化完成,在赋值
执行这个方法,输出构造函数打印的语句,说明底层通过Java反射机制初始化的
在这之前,我们的对象属于婴儿对象,因为它的属性还没有赋值。都是称为婴儿对象。
那么什么时候赋值呢?
populateBean(beanName, mbd, instanceWrapper);//这里给对象属性赋值
在给对象属性赋值之前:
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);}} }
A对象坚持依赖B对象,这时候B对象也需要被创建
A对象已经存放在三级缓存中,这时候要去创建B对象
此时B对象也要走A对象流程
看下调用链
也将B对象放入三级缓存
总结下:
AService在创建的时候,提前曝光存放到三级缓存中,AService发现依赖BService,这时候Bservice提前曝光存放到三级缓存中去。
此时BService又依赖AService,此时BService经过赋值是完整对象,但是Aservice还是婴儿对象,没有完全创建完毕。
就会去把BService对象注册到一级缓存中,同时会把之前缓存BService对象的二级缓存清除掉
AService对象依赖BService,BService此时已经创建成功了,那么AService在设置属性后,就直接把BService赋值给AService。
开始注册AService对象
总结:
SpringBean中 Aservic对象被创建流程步骤源码分析:
- doGetBean创建我们bean对象
- getSingleton (beanName) 获取缓存对象
注意:完整对象概念:对象已经实例化成功并且所有属性都已经赋值
- singletonObjects 一级缓存完整对象
- earlySingletonObjects 二级缓存 缓存婴儿对象
- singletonFactories 三级缓存存放婴儿对象
理解概念:
- 完整对象表示该对象实例化完成并且所有的属性已经赋值。
- 婴儿对象(提前对象)对象已经实例化完成但是属性没有赋值的。
singletonObject ==null&&this.singletonsCurrentlyInCreation.contains(beanName);
{
才能够查询二级缓存
}
singletonsCurrentlyInCreation :标记为该对象开始创建
- getSingleton(String beanName, ObjectFactory<?> singletonFactory)
this.singletonsCurrentlyInCreation.add(beanName) 表示该对象已经开始创建
- createBean() →doCreateBean
- addSingletonFactory 将婴儿对象(不完整对象也就是只是实例化完成但是属性没有赋值的) 存放三级缓存中。
- A对象已经存放到三级缓存中,开始给对象属性赋值的时候 需要创建B对象。
A对象检查发现依赖B对象 这时候B对象也需要被创建
本文参考:
蚂蚁课堂
http://www.mayikt.com/