spring ioc源码层看spring循环依赖的问题

首先,什么是循环依赖?

spring ioc源码层看spring循环依赖的问题_第1张图片

如上图所示bean的创建流程:创建A----实例化-->依赖b---->创建B----->依赖a---->创建A
出现了闭环,也就是spring的循环依赖
bean的后置处理器9处调用
spring ioc源码层看spring循环依赖的问题_第2张图片
spring ioc在创建bean过程中,会调用8次bean的后置处理器BeanPostProcessor,第九次是在bean销毁的时候调用
spring ioc源码层看spring循环依赖的问题_第3张图片

在bean的创建过程中,bean可被划分为四种形态:概念态的bean、定义态的bean、纯洁态的bean、成熟态的bean

其中:成熟态的bean被放在单例池,也就是一级缓存中singletonObjects(其实是个map,new ConcurrentHashMap<>(256))

先去一级缓存中拿bean,因为不是所有的bean都存在循环依赖;正常创建的单实例bean,都存放在一级缓存中

//一级缓存  这个就是我们大名鼎鼎的单例缓存池,用于保存我们所有的单实例bean
private final Map singletonObjects = new ConcurrentHashMap<>(256);
singletonObjects.put(beanName,bean);    //beanName为bean的名称,bean是实例化产生的bean,put操作是在bean初始化之后执行的 

纯洁态的bean会被放在二级缓存中

循环依赖的创建流程:创建A----实例化-->依赖b---->创建B----->依赖a---->创建A
线程在bean实例化之后就放入一级缓存了,此时b尚未进行赋值,如果此时有别的线程调用a,而B尚未创建赋值到b,此时这线程得到的a会是一个不完整的bean
所以需要二级缓存,用来存放尚未来得及赋值的bean

//二级缓存  用户缓存我们的key为beanName,value是我们的早期对象(对象属性还没有来得及进行赋值)
private final Map earlySingletonObjects = new HashMap<>(16);

三级缓存中存放的是,被spring aop切点命中的bean,产生的动态代理

一般情况下,spring aop的动态代理是在bean初始化之后进行创建的
但是如果出现循环依赖的情况,动态代理会在bean实例化之后就进行动态代理的创建(此处会根据标志符判断,是否循环依赖),并返回动态代理(不是返回实例对象),并存放在三级缓存中

//三级缓存  该map用来缓存key为beanName   value为ObjectFactory(包装为早期对象)
private final Map> singletonFactories = new HashMap<>(16);

spring ioc源码层看spring循环依赖的问题_第4张图片

Aop的核心的动态代理,正常流程aop的动态代理是在bean的初始化之后,通过bean的后置处理器进行创建的

循环依赖只存在于bean当中,对象不存在循环依赖
原因是在spring中,bean的创建交给了spring ioc容器,spring通过反射生成bean对象。在bean创建的生命周期当中,循环依赖是在实例化之后,属性赋值的阶段产生的。而通过new出来的对象,不存在此问题。
@lombok
public class BeanA{
    @Autowried
    private BeanB b;
    private String name;
    private Integer age;
}
@lombok
public class BeanB{
    @Autowried
    private BeanA a;
    private String name;
    private Integer age;
}

public class MainStar{
    BeanA a = new BeanA();
    BeanB b = new BeanB();
    a.setBeanB(b);
    b.setEeanA(a);
}    //这是可以的,没有问题。
/**
* 模拟Spring ioc的实现流程
* @author fmm
* @date 2020/8/28
*/
public class MainStar {
    public static void main(String[] args) throws Exception{
        //假设已经加载了循环依赖
        String beanName = "com.fmm.learning.entity.InstanceA";
        /**
         * createBean(beanName);到这里就相当于ApplicationContext已经加载了spring容器
         * 相当于AnnotationConfigApplicationContext tx = new AnnotationConfigApplicationContext(MainStar.class);
         */
//        createBean(beanName);
        getBean(beanName);


        //此处如果beanName是乱写的,也会出现在一级缓存中获取不到的情况
        InstanceA instanceA = (InstanceA) getBean(beanName);
        instanceA.say();
    }


    //一级缓存  单例池     存储成熟态的bean
    private static final Map singletonObjects = new ConcurrentHashMap<>(256);


    //二级缓存  存储纯洁态的bean(存储不完整的Bean用于解决循环依赖中多线程读取一级缓存中的脏数据)
    private static final Map earlySingletonObjects = new HashMap<>(16);


    //三级缓存  函数指针
    private static final Map> singletonFactories = new HashMap<>(16);




    //该集合用户缓存当前正在创建bean的名称
    // 用来标识是否循环依赖,  如果正在创建并且从一级缓存中没有获取到bean,说明产生循环依赖
    private static final Set singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));


    /**
     * 获取bean
     */
/*    private static Object getBean(String beanName) {
        return singletonObjects.get(beanName);
    }*/


    /**
     * 创建bean
     * @param beanName
     */
    private static Object getBean(String beanName) throws Exception{


        Class beanClass = Class.forName(beanName);


        //获取单实例bean
        Object bean = getSingleton(beanName);
        //如果获取到了bean,就直接返回,不用再创建了
        if(bean!=null){
            return bean;
        }


        //如果没有获取到,进行创建
        //创建bean的过程


        //添加bean的状态标识,用于判断当前bean是否正在被创建
        singletonsCurrentlyInCreation.add(beanName);


        //1.实例化
        Object beanInstance = beanClass.newInstance();


        ObjectFactory factory = ()->{
           return getEarlyBeanReference(beanName,beanInstance);
        };


        //存储到三级缓存
        singletonFactories.put(beanName,factory);


        /**
         * spring为了解决aop下面的循环依赖,会在此处创建动态代理  Proxy.newProxyInstance()
         * 动态代理是由Bean的后置处理器SmartInstantiationAwareBeanPostProcessor.getEarlyBeanReference()创建的
         * 用来解耦,同时可以提高扩展性;Spring是不会将aop和ioc写在一起的
         * 不能将创建动态代理的代码和IOC的代码耦合,所以不放在二级缓存,使用三级缓存
         *
         * 不是所有的bean都存在循环依赖,不是所有的bean都实现了aop
         * 在这里应该加入判断,当创建的当前bean是循环依赖,并且被aop切点命中
         * 才去调用aop的后置处理器创建动态代理
         * 不存在循环依赖的,在bean的初始化之后,创建aop动态代理
         */
        //此处要求是在循环依赖并且实现aop的情况下才在此创建动态代理
//        JdkProxyBeanPostProcessor beanPostProcessor = new JdkProxyBeanPostProcessor();
//        beanPostProcessor.getEarlyBeanReference(beanInstance,beanName);


        //放入到二级缓存中
//        earlySingletonObjects.put(beanName,beanInstance);


        //2.属性赋值    解析AutoWired
        //拿到所有的属性名
        Field[] declaredFields = beanClass.getDeclaredFields();


        //循环所有的属性名
        for (Field declaredField : declaredFields) {
            //查找标注有@AutoWired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            //说明属性上面有注解
            if(annotation!=null){
                Class type = declaredField.getType();
                /**
                 * 查找到InstanceA中有标注了autowired注解的属性InstanceB,优先加载InstanceB
                 * type.getName() = com.fmm.learning.entity.InstanceB
                 * 递归思想
                 */
                getBean(type.getName());
            }
        }


        //3.初始化 (省略)
        //创建动态代理




        //存入到一级缓存
        singletonObjects.put(beanName,beanInstance);


        return beanInstance;
    }


    private static Object getSingleton(String beanName) {
        //1.先从一级缓存中获取,一级缓存中没有获取到,说明产生了循环依赖
        Object bean = singletonObjects.get(beanName);
        //如果一级缓存中不存在,再在二级缓存中去获取
        //singletonsCurrentlyInCreation.contains(beanName),确定当前bean正在创建
        if(bean==null && singletonsCurrentlyInCreation.contains(beanName)){


            bean = earlySingletonObjects.get(beanName);
            //如果二级缓存中没有,去三级缓存中拿
            if(bean==null){
                //确认当前bean正在创建,并且实现了aop,此时调用bean的后置处理器创建动态代理
                ObjectFactory factory = singletonFactories.get(beanName);
                //通过调用factory.getObject(),函数指针会指向getEarlyBeanReference,进行动态代理的创建
                factory.getObject();
            }
        }
        return bean;
    }


    //创建动态代理
    private static Object getEarlyBeanReference(String beanName,Object bean){
//        JdkProxyBeanPostProcessor beanPostProcessor = new JdkProxyBeanPostProcessor();
//        beanPostProcessor.getEarlyBeanReference(beanInstance,beanName);
        return null;
    }
}

这里只是简单的模拟了一下spring ioc实现流程,以及在bean的哪个生命周期产生了spring的循环依赖问题,以及如何使用三级缓存进行解决的,为什么需要使用三级缓存。

扩展:

1.能不能解决构造函数中的循环依赖?为什么?

不能

2.能不能解决多实例Bean的循环依赖?为什么?

不能

你可能感兴趣的:(Spring学习,java,spring,后端)