Spring 循环依赖

Spring 循环依赖

chuxiwen 2,760 2023-03-08

Spring 循环依赖

循环依赖的产生

spring_cycle_1
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_cycle_2

设置一个出口

在循环依赖中,如果存在一个出口,打破这个循环,就可以解决循环依赖,spring设置缓存进行处理。
spring_cycle_3

修改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_cycle_4

很奇怪!好像一层就解决了Spring循环依赖问题了?那众所周知,Spring三层缓存,难不成一层有难,两层围观??当然不是,继续唠。


# Spring 学习