mysql循环依赖_5.6循环依赖

5.6.1什么是循环依赖、循环调用

循环依赖:实例化bean是一个复杂的过程。循环依赖就是两个或者多个bean相互之间持有对方,比如TestA引用TestB,TestB引用TestA,则它们最终反映为一个环。

循环调用:循环调用是方法之间的环调用。循环调用是无法解决的,除非有终结条件,否则就是死循环,最终导致内存溢出。

5.6.2Spring如何解决循环依赖

首先我们定义循环依赖类、注入、测试方法

packageCircularReference;public classTestA {privateTestB testB;publicTestA(){

}publicTestA(TestB testB) {this.testB =testB;

}publicTestB getTestB() {returntestB;

}public voidsetTestB(TestB testB) {this.testB =testB;

}

}packageCircularReference;public classTestB {privateTestA testA;publicTestB(){

}publicTestB(TestA testA) {this.testA =testA;

}publicTestA getTestA() {returntestA;

}public voidsetTestA(TestA testA) {this.testA =testA;

}

}

/*** 构造器循环依赖*/@Testpublic voidconstructor(){try{new ClassPathXmlApplicationContext("/circularReference.xml");

}catch(Exception e){

e.printStackTrace();

System.out.println(e.getCause());

}

}/*** setter循环依赖*/@Testpublic voidsetter(){

ApplicationContext contex=

new ClassPathXmlApplicationContext("/circularReference.xml");

System.out.println(contex.getBean("testA"));

}

3种循环依赖

1)构造器循环依赖(单例的)

构造器注入的循环依赖,此依赖是无法解决的。只能抛出BeanCurrentlyInCreationEx-ception异常表示循环依赖。与bean实例化有关。

代码中的实现方式:DefaultSingletonBeanRegistry中getSingleton(beanName-->,singletonFactory)方法的beforeSingletonCreation中的this.singletonsCurrently-InCreation.add(beanName)。5.4获取单例---大致逻辑---第3条。

Spring容器将每一条正在创建的bean标识符放在一个“当前创建bean池”中,bean标识符在创建过程中将一直保持在这个池中,因为如果在创建bean过程中发现自己已经在“当前创建bean池”里面时,抛出BeanCurrentlyInCreationEx-ception异常表示循环依赖。而对于创建完毕的bean将从“当前创建bean池”中移除。

模拟执行:

Spring容器创建“testA” bean,首先去“当前创建 bean 池” 查找是否当前 bean 正在创建,如果没发现,则继续准备其需妥的构造器参数“testB”,并将“testA”标识符放到“当前创建池”中。

Spring容器创建“testB”bean,首先去“当前创建 bean池”查找是否当前 bean 正在创建 ,如没发现,则继续准备其需妥 的构造 器参数“ testA”,并将“ testB”标识符放到“当前创建bean池”。

到此为止 Spring 容器要去创建“testA” bean,发现该 bean 标识符在“当前创建 bean 池”中,因为表示循环依赖,抛出 BeanCurrentlyInCreationException

2)setter循环依赖(单例的)

简单来说是通过一个默认构造器,并暴露一个FactoryBean用于返回一个创建中的bean(AbstractBeanFactory.doGetBean方法的getSingleton会用到),然后再进行setter设置。

通过setter注入方式构成的循环依赖。对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入(默认构造器)但未完成其他步骤(如setter注入)的bean来完成的,而且只能解决单例作用域的bean循环依赖。通过提前暴露一个单例工厂方法,从而使其他bean能引用到该bean。

代码中的实现方式:

获取:AbstractBeanFactory-->doGetBean-->getSingleton

protected Object getSingleton(String beanName, booleanallowEarlyReference) {//Quick check for existing instance without full singleton lock//检查缓存中是否存在实例

Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null &&isSingletonCurrentlyInCreation(beanName)) {//缓存中没有实例但是又在创建中,那么可能是循环依赖,解决循环依赖的方式是//Spring创建bean的原则是不等bean创建完成就会创建bean的ObjectFactory提早曝光

singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null &&allowEarlyReference) {//如果为空,则锁定全局变量并进行处理

synchronized (this.singletonObjects) {//Consistent creation of early reference within full singleton lock

singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {

singletonObject= this.earlySingletonObjects.get(beanName);if (singletonObject == null) {//当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的//ObjectFactory初始化策略存储在singletonFactories

ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {//调用预先设定的getObject方法

singletonObject =singletonFactory.getObject();//记录在缓存中,earlySingletonObjects和singletonFactories互斥

this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);

}

}

}

}

}

}returnsingletonObject;

}

存储:AbstractAutowireCapableBeanFactory-->createBean-->doCreateBean-->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);

}

}

}

3)prototype范围的依赖处理

对于prototype作用域bean,Spring容器无法完成依赖注入,因为Spring容器不进行缓存“prototype”作用域的bean。因此无法暴露一个创建中的bean。

对于singleton作用域bean,可以通过“setAllowCircularReferences(false)”来禁止循环引用。

博客:Spring中循环引用的处理

https://www.iflym.com/index.php/code/201208280001.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值