Spring 循环依赖
循环依赖的产生
A类的成员变量中存在B,而B类中存在A类,相互依赖,导致一个闭环,通过构造参数无限递归,产生死循环
产生循环依赖的代码
A
@Component
@Data
public class A {
@Autowired
private B b;
public A(){
System.out.println("A 实例化...");
}
public void say(){
System.out.println("A say ...");
}
}
B
@Component
@Data
public class B {
@Autowired
private A a;
public B(){
System.out.println("B 实例化...");
}
public void say(){
a.say();
}
}
Main
private static final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
/**
* 读取bean定义,当然在spring中肯定是根据配置 动态扫描注册
*/
public static void loadBeanDefinitions() {
RootBeanDefinition aBeanDefinition = new RootBeanDefinition(A.class);
RootBeanDefinition bBeanDefinition = new RootBeanDefinition(B.class);
// spring默认的类的类名开头小写,所以map的名字应该是小写,否则会出现空指针异常
beanDefinitionMap.put("a", aBeanDefinition);
beanDefinitionMap.put("b", bBeanDefinition);
}
public static void main(String[] args) throws Exception {
// 加载了BeanDefinition
loadBeanDefinitions();
// 注册Bean的后置处理器
// 循环创建Bean
for (String key : beanDefinitionMap.keySet()) {
// 先创建A
getBean(key);
}
B b = (B) getBean("b");
b.say();
}
public static Object getBean(String beanName) throws Exception {
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
// 通过无参构造函数
Object instanceBean = beanClass.newInstance();
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Autowired annotation = declaredField.getAnnotation(Autowired.class);
// 说明属性上面有Autowired
if (annotation != null) {
// 可以操作private标注的成员变量
declaredField.setAccessible(true);
String name = declaredField.getName();
Object fileObject = getBean(name); //拿到B得Bean
declaredField.set(instanceBean, fileObject);
}
}
return instanceBean;
}
运行结果 栈溢出-> java.lang.StackOverflowError
设置一个出口
在循环依赖中,如果存在一个出口,打破这个循环,就可以解决循环依赖,spring设置缓存进行处理。
修改Main代码
private static final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
// 一级缓存
public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
/**
* 读取bean定义,当然在spring中肯定是根据配置 动态扫描注册
*/
public static void loadBeanDefinitions() {
RootBeanDefinition aBeanDefinition = new RootBeanDefinition(A.class);
RootBeanDefinition bBeanDefinition = new RootBeanDefinition(B.class);
beanDefinitionMap.put("a", aBeanDefinition);
beanDefinitionMap.put("b", bBeanDefinition);
}
public static void main(String[] args) throws Exception {
// 加载了BeanDefinition
loadBeanDefinitions();
// 注册Bean的后置处理器
// 循环创建Bean
for (String key : beanDefinitionMap.keySet()) {
// 先创建A
// 递归出来后更新一下map
getBean(key);
}
B b = (B) getBean("b");
b.say();
}
public static Object getBean(String beanName) throws Exception {
// 如果map中有就返回,不管是不是完整的对象
Object o = singletonObjects.get(beanName);
if (o != null) {
return o;
}
// 实例化
RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
Class<?> beanClass = beanDefinition.getBeanClass();
// 通过无参构造函数
Object instanceBean = beanClass.newInstance();
// 添加到一级缓存 A
singletonObjects.put(beanName, instanceBean);
// 属性赋值
Field[] declaredFields = beanClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
Autowired annotation = declaredField.getAnnotation(Autowired.class);
// 说明属性上面有Autowired
if (annotation != null) {
declaredField.setAccessible(true);
String name = declaredField.getName();
Object fileObject = getBean(name); //拿到B得Bean
declaredField.set(instanceBean, fileObject);
}
}
return instanceBean;
}
运行结果
很奇怪!好像一层就解决了Spring循环依赖问题了?那众所周知,Spring三层缓存,难不成一层有难,两层围观??当然不是,继续唠。