循环依赖的解决

是什么

循环依赖,也就是两个或者两个以上的bean互相持有对方,最终形成闭环。
比如A依赖于B,B依赖于C,C又依赖于A。如下图:
在这里插入图片描述

代码中的体现

@Component
public class A {
    // A中注入了B
    @Autowired
    private B b;
}

@Component
public class B {
    // B中也注入了A
    @Autowired
    private A a;
}

解决循环依赖的本质

先去缓存Map里找Bean,没有则实例化当前的Bean放到Map,如果有需要依赖当前Bean的,就能从Map取到。
可以这么理解,当调用A的构造函数后,放入缓存Map中,在要注入属性B时。就去创建属性B,发现要注入属性A,从缓存中已经可以获取到创建好的A(虽然只是调用了构造函数,暴露了A的引用)。B创建好后返回创建A。这个时候循环依赖就解决了。

代码体现

public class Main {
    private static Map<String, Object> cacheMap = new HashMap<>(4);

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 假装扫描出来的对象
        Class[] classes = {A.class, B.class};
        // 假装项目初始化实例化所有bean
        for (Class aClass : classes) {
            getBean(aClass);
        }
        // check
        System.out.println(getBean(B.class).getA() == getBean(A.class));
        System.out.println(getBean(A.class).getB() == getBean(B.class));
        //在调用链可以是main->A->B
        //不可以是main->A->B->A->....比如直接输出B
        System.out.println(getBean(A.class).helllo());
    }

    private static <T> T getBean(Class<T> beanClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 本文用类名小写 简单代替bean的命名规则
        String beanName = beanClass.getSimpleName().toLowerCase();
        // 如果已经是一个bean,则直接返回
        if (cacheMap.containsKey(beanName)) {
            return (T) cacheMap.get(beanName);
        }
        // 将对象本身实例化
        Object object = beanClass.getDeclaredConstructor().newInstance();
        // 放入缓存
        cacheMap.put(beanName, object);
        // 把所有字段当成需要注入的bean,创建并注入到当前bean中
        Field[] fields = object.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            // 获取需要注入字段的class
            Class<?> fieldClass = field.getType();
            String fieldBeanName = fieldClass.getSimpleName().toLowerCase();
            // 如果需要注入的bean,已经在缓存Map中,那么把缓存Map中的值注入到该field即可
            // 如果缓存没有 继续创建
            if (cacheMap.containsKey(fieldBeanName)){
                field.set(object,cacheMap.get(fieldBeanName));
            }else {
                field.set(object,getBean(fieldClass));
            }
        }
        // 属性填充完成,返回
        return (T) object;
    }
}
/**
 * @author shunda wu
 * @date 2020/8/10
 **/
public class A {
    private B b;
    public A() {
    }
    public B getB() {
        return b;
    }
    public void setB(B b) {
        this.b = b;
    }
    public String helllo(){
        return b.helllo();
    }
    @Override
    public String toString() {
        return "A{" +
                "b=" + b +
                '}';
    }
}
/**
 * @author shunda wu
 * @date 2020/8/10
 **/
public class B {
    private A a;
    public B() {
    }
    public A getA() {
        return a;
    }
    public void setA(A a) {
        this.a = a;
    }
    public String helllo(){
        return "hello";
    }
    @Override
    public String toString() {
        return "B{" +
                "a=" + a +
                '}';
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值