循环依赖就是循环引用,在spring中,就是两个或者多个bean相互之间持有对方。如下图,ClassA引用ClassB,ClassB引用ClassC,ClassC又引用ClassA,最终它们形成了一个环,这就是循环依赖。
spring中将循环依赖分成了3中情况,分别是:
通过构造器注入构成的循环依赖, 此依赖无法解决
。在Spring中会抛出BeanCurrentlyInCreationException异常表示循环依赖。
对于构造器注入构成的循环依赖,在创建ClassA的时候,构造器需要ClassB,然后去创建ClassB,在创建ClassB的时候发现需要ClassA,形成了一个死循环,无法完成创建。
对于 prototype
作用域的bean,spring容器无法完成依赖注入,因为spring不像缓存单例那样缓存prototype作用域的bean。
表示通过setter注入方式构成的循环依赖,spring通过提前暴露构造器注入但未完成其他步骤(如setter操作)的bean来完成setter注入造成的循环依赖。
自己简单的用代码来展示spring解决单例setter循环依赖的方式,具体spring中如何解决感兴趣可以自己阅读源码。
创建两个循环依赖的类,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用来模仿Spring解决循环依赖获取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 { /**用于缓存正在初始化中的对象,同时作为提前暴露的缓存*/ private static final Map<Class, Object> currentInitObjects = new ConcurrentHashMap<>(); /**用于缓存初始化好的单例对象*/ private static final Map<Class, Object> objects = new ConcurrentHashMap<>(); /** * 获取对象,并设值对象属性。 * 1. 不考虑并发问题,简单的示例 * 2. 解决单例setter循环依赖 * * @param cls * @param <T> * @return */ public <T> T getObject(Class<T> cls) { //如果已经初始化过直接返回 if (objects.containsKey(cls)) { return (T) objects.get(cls); } try { T t; //1. 简单的使用构造函数创建对象,并提前暴露到currentInitObjects中 t = cls.newInstance(); //提前暴露到currentInitObjects中 currentInitObjects.put(cls, t); //2. 解决依赖属性值 resolveDependence(t, cls); //3. 放入单例缓存中 objects.put(cls, t); return t; } catch (Exception e) { System.out.println("初始化对象失败:" + cls); return null; } finally { //4. 从正在初始化缓存中移除 currentInitObjects.remove(cls); } } /** * 解决依赖属性设值. * @param object 对象 * @param cls 对象class */ private void resolveDependence(Object object, Class cls) { //获取对象的属性,并进行赋值,省去了复杂的判断,就认为是对象 //1.获取所有属性 Field[] fields = cls.getDeclaredFields(); //2.循环处理属性值 Arrays.stream(fields).forEach(field -> { field.setAccessible(true); //2.1 获取属性class属性 Class fieldClass = field.getType(); Object value; //2.2 判断是否已经初始化过 if (objects.containsKey(fieldClass)) { value = objects.get(fieldClass); } else if (currentInitObjects.containsKey(fieldClass)) { //2.3 判断当前初始化的类中有没有这个属性. value = currentInitObjects.get(fieldClass); } else { //2.4 如果都没有,进行初始化 value = getObject(fieldClass); } //3. 使用反射设置属性的值 try { field.set(object, value); } catch (IllegalAccessException e) { System.out.println("设置对象属性失败:" + cls + "-" + field.getName()); } }); } }
客户端调用
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("-----我是分割线-----"); 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 -----我是分割线----- I am ClassA classB.getClassA() == classA:true classA.getClassB() == classB:true
从输出可以发现: