什么是循環(huán)依賴(lài)
循環(huán)依賴(lài)就是循環(huán)引用,在spring中,就是兩個(gè)或者多個(gè)bean相互之間持有對(duì)方。如下圖,ClassA引用ClassB,ClassB引用ClassC,ClassC又引用ClassA,最終它們形成了一個(gè)環(huán),這就是循環(huán)依賴(lài)。
Spring中的循環(huán)依賴(lài)
spring中將循環(huán)依賴(lài)分成了3中情況,分別是:
- 構(gòu)造器循環(huán)依賴(lài)
- prototype范圍的依賴(lài)處理
- setter循環(huán)依賴(lài)
構(gòu)造器循環(huán)依賴(lài)
通過(guò)構(gòu)造器注入構(gòu)成的循環(huán)依賴(lài),此依賴(lài)無(wú)法解決。在Spring中會(huì)拋出BeanCurrentlyInCreationException異常表示循環(huán)依賴(lài)。
對(duì)于構(gòu)造器注入構(gòu)成的循環(huán)依賴(lài),在創(chuàng)建ClassA的時(shí)候,構(gòu)造器需要ClassB,然后去創(chuàng)建ClassB,在創(chuàng)建ClassB的時(shí)候發(fā)現(xiàn)需要ClassA,形成了一個(gè)死循環(huán),無(wú)法完成創(chuàng)建。
prototype范圍的依賴(lài)處理
對(duì)于prototype作用域的bean,spring容器無(wú)法完成依賴(lài)注入,因?yàn)閟pring不像緩存單例那樣緩存prototype作用域的bean。
setter循環(huán)依賴(lài)
表示通過(guò)setter注入方式構(gòu)成的循環(huán)依賴(lài),spring通過(guò)提前暴露構(gòu)造器注入但未完成其他步驟(如setter操作)的bean來(lái)完成setter注入造成的循環(huán)依賴(lài)。
自己簡(jiǎn)單的用代碼來(lái)展示spring解決單例setter循環(huán)依賴(lài)的方式,具體spring中如何解決感興趣可以自己閱讀源碼。
創(chuàng)建兩個(gè)循環(huán)依賴(lài)的類(lèi),ClassA和ClassB。
package io.github.brightloong.lab.spring.cyclicdependence;
/**
* @author BrightLoong
* @date 2018/9/13 11:17
* @description
*/
public class ClassA {
private ClassB classB;
public ClassB getClassB() {
return classB;
}
public void setClassB(ClassB classB) {
this.classB = classB;
}
public void say() {
System.out.println("I am ClassA");
}
}
package io.github.brightloong.lab.spring.cyclicdependence;
/**
* @author BrightLoong
* @date 2018/9/13 11:17
* @description
*/
public class ClassB {
private ClassA classA;
public ClassA getClassA() {
return classA;
}
public void setClassA(ClassA classA) {
this.classA = classA;
}
public void say() {
System.out.println("I am ClassB. Who are you?");
classA.say();
}
}
ObjectFactory用來(lái)模仿Spring解決循環(huán)依賴(lài)獲取bean
package io.github.brightloong.lab.spring.cyclicdependence;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author BrightLoong
* @date 2018/9/13 11:19
* @description
*/
public class ObjectFactory {
/**用于緩存正在初始化中的對(duì)象,同時(shí)作為提前暴露的緩存*/
private static final Map<Class, Object> currentInitObjects = new ConcurrentHashMap<>();
/**用于緩存初始化好的單例對(duì)象*/
private static final Map<Class, Object> objects = new ConcurrentHashMap<>();
/**
* 獲取對(duì)象,并設(shè)值對(duì)象屬性。
* 1. 不考慮并發(fā)問(wèn)題,簡(jiǎn)單的示例
* 2. 解決單例setter循環(huán)依賴(lài)
*
* @param cls
* @param <T>
* @return
*/
public <T> T getObject(Class<T> cls) {
//如果已經(jīng)初始化過(guò)直接返回
if (objects.containsKey(cls)) {
return (T) objects.get(cls);
}
try {
T t;
//1. 簡(jiǎn)單的使用構(gòu)造函數(shù)創(chuàng)建對(duì)象,并提前暴露到currentInitObjects中
t = cls.newInstance();
//提前暴露到currentInitObjects中
currentInitObjects.put(cls, t);
//2. 解決依賴(lài)屬性值
resolveDependence(t, cls);
//3. 放入單例緩存中
objects.put(cls, t);
return t;
} catch (Exception e) {
System.out.println("初始化對(duì)象失?。? + cls);
return null;
} finally {
//4. 從正在初始化緩存中移除
currentInitObjects.remove(cls);
}
}
/**
* 解決依賴(lài)屬性設(shè)值.
* @param object 對(duì)象
* @param cls 對(duì)象class
*/
private void resolveDependence(Object object, Class cls) {
//獲取對(duì)象的屬性,并進(jìn)行賦值,省去了復(fù)雜的判斷,就認(rèn)為是對(duì)象
//1.獲取所有屬性
Field[] fields = cls.getDeclaredFields();
//2.循環(huán)處理屬性值
Arrays.stream(fields).forEach(field -> {
field.setAccessible(true);
//2.1 獲取屬性class屬性
Class fieldClass = field.getType();
Object value;
//2.2 判斷是否已經(jīng)初始化過(guò)
if (objects.containsKey(fieldClass)) {
value = objects.get(fieldClass);
} else if (currentInitObjects.containsKey(fieldClass)) {
//2.3 判斷當(dāng)前初始化的類(lèi)中有沒(méi)有這個(gè)屬性.
value = currentInitObjects.get(fieldClass);
} else {
//2.4 如果都沒(méi)有,進(jìn)行初始化
value = getObject(fieldClass);
}
//3. 使用反射設(shè)置屬性的值
try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("設(shè)置對(duì)象屬性失?。? + cls + "-" + field.getName());
}
});
}
}
客戶(hù)端調(diào)用
package io.github.brightloong.lab.spring.cyclicdependence;
/**
* @author BrightLoong
* @date 2018/9/13 11:19
* @description
*/
public class Client {
public static void main(String[] args) {
ObjectFactory factory = new ObjectFactory();
ClassB classB = factory.getObject(ClassB.class);
classB.say();
System.out.println("-----我是分割線(xiàn)-----");
ClassA classA = factory.getObject(ClassA.class);
classA.say();
System.out.println("classB.getClassA() == classA:" + (classB.getClassA() == classA));
System.out.println("classA.getClassB() == classB:" + (classA.getClassB() == classB));
}
}
輸出如下:
I am ClassB. Who are you?
I am ClassA
-----我是分割線(xiàn)-----
I am ClassA
classB.getClassA() == classA:true
classA.getClassB() == classB:true
從輸出可以發(fā)現(xiàn):
- ClassA和ClassB都成功實(shí)例化
- 都是單例