手写IOC-解决循环依赖

874 阅读1分钟

github地址: github.com/zexho994/IO…

解决循环依赖

在spring中使用“3级缓存”来解决循环依赖问题,不要纠结spring为何要使用3个map来实现,抛开实现的细节,从问题原因着手,这个问题其实使用很好理解。

何为循环依赖?

下面的A和B就互相依赖彼此,这样就会有一个问题,在创建A的时候需要创建B,但是创建B的时候又需要创建A,看起来像是一个先有鸡还是蛋的问题。

@Bean
public class ClassA {
    @Autowired
    public ClassB ib;

}

@Bean
public class ClassB {
    @Autowired
    public ClassA ia;
    
}

但是要知道Bean的创建其实是分为多个步骤的,就好理解了。

graph LR
n0(start) --> n1(创建instance) --> n2(填充需要注入的fields字段) --> n3(end)

在创建完instance后,里面的字段其实都还是null的,例如已经创建ClassA实例a,和ClassB实例b,此时a.ib = nullb.ia = null. 然后赋值 a.ib = bb.ia = a,这之后,a和b中的字段都赋值完了,且都是完整可用的对象了。

public Object getBean(String beanName) {
    BeanDefinition bean = this.getBeanInstance(beanName);
    if (!bean.isInit()) {
        try {
            this.initBean(bean);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    return bean.getInstance();
}

// 初始化bean
private void initBean(BeanDefinition beanDefinition) throws IllegalAccessException {
    Object instance = beanDefinition.getInstance(); // 获取bean的isntance
    beanDefinition.setStatusInitialized();  //设置为已初始化
    this.initAutowire(instance);
}

// 遍历所有字段,为有@Authwired注解的实现注入
private void initAutowire(Object instance) throws IllegalAccessException {
    Field[] fields = instance.getClass().getFields();
    for (Field field : fields) {
        if (field.getDeclaredAnnotationsByType(Autowired.class).length == 0) {
            continue;
        }
        Class<?> fieldType = field.getType();
        Object bean = this.getBean(fieldType.getSimpleName());
        field.set(instance, bean);  //field赋值
    }
}

有一个比较好的类比,leetcode的一道算法题two sum leetcode-cn.com/problems/tw…,其中一种题解就是遍历一边,存储所有值和索引到map中,然后遍历一次map,每次判断是否有要的数。

这个也是,先讲instance存到map中,然后把map中instance的fields都进行填充,就可以了。