Spring循环依赖

Spring循环的问题模拟

  1. 先准备两个实例
package com.sw.swtest.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 8:45
 * @description :
 */
@Component
public class InstanceA {

    @Autowired
    private InstanceB instanceB;

    public InstanceB getInstB() {
        return instanceB;
    }

    public void setInstB(InstanceB instB) {
        this.instanceB = instB;
    }

    public InstanceA() {
        System.out.println("InstanceA的构造方法");
    }

    @Override
    public String toString() {
        return "InstanceA{}";
    }
}

package com.sw.swtest.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 8:46
 * @description :
 */
@Component
public class InstanceB {
    @Autowired
    private InstanceA instanceA;

    public InstanceA getInstanceA() {
        return instanceA;
    }

    public void setInstanceA(InstanceA instanceA) {
        this.instanceA = instanceA;
    }

    public InstanceB() {
        System.out.println("InstanceB的构造方法");
    }

    @Override
    public String toString() {
        return "InstanceB{}";
    }
}

2.会出现循环依赖的现象,尽量的去模拟Spring(我模拟的比较简单)

package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {
        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();


        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)

        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        return instanceBean;
    }


}

  1. 运行结果如下: 死循环循环依赖报错
    循环依赖现象: 循环创建Bean的时候,BeanA依赖于BeanB,BeanB又依赖于BeanA,重复创建死循环
package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
        InstanceA instanceA = (InstanceA) getBean("instanceA");
        System.out.println(instanceA);
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {

        //给循环依赖添加出口
        Object singleton = getSingleton(beanName);
        if(singleton!= null){
            return singleton;
        }


        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();


        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)

        return instanceBean;
    }


    public static Object getSingleton(String beanName){
        //先从一级缓存中拿
        if(singletonObjects.containsKey(beanName)){
           return singletonObjects.get(beanName);
        }
        return null;
    }

}

解决循环依赖: 就是给循环依赖添加一个出口getSingleton(), 如果一级缓存中有就返回一级缓存中的对象,如果没有返回空,
(注意:放入一级缓存的时机需要调整到属性赋值之前)

流程: beanA 实例化==>beanA放入一级缓存 ==>属性赋值 ==>beanB 实例化 ==> beanB放入一级缓存 ==>属性赋值获取beanA 此时拿到的beanA就是不完整的bean

结论: 一级缓存就可以解决循环依赖,但是并发时会出现问题,会拿到不完整的bean(如果硬要钻牛角尖的话,一级缓存就可以解决循环依赖了,加锁解决并发也可以,但是毕竟是Spring,职能划分很明确,因此才有了二级缓存)

面试(美团): Spring是怎么避免读取到不完整的bean?
答: Spring引入了二级缓存earlySingletonObjects , 为了将成熟bean和纯净bean分离开,避免读取到不完整的bean, 只实例化没有属性赋值的纯净bean就存入二级缓存中,属性赋值初始化之后的bean存入一级缓存

package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
        InstanceA instanceA = (InstanceA) getBean("instanceA");
        System.out.println(instanceA);
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {

        //给循环依赖添加出口
        Object singleton = getSingleton(beanName);
        if(singleton!= null){
            return singleton;
        }


        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();


        //添加到二级缓存
        earlySingletonObjects.put(beanName, instanceBean);

        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)

        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        return instanceBean;
    }


    public static Object getSingleton(String beanName){
        //先从一级缓存中拿
        if(singletonObjects.containsKey(beanName)){
           return singletonObjects.get(beanName);
           //一级缓存拿不到从二级缓存中拿
        }else if (earlySingletonObjects.containsKey(beanName)){
            return earlySingletonObjects.get(beanName);
        }
        return null;
    }

}

实例化后属性赋值之前的纯净bean放入二级缓存,初始化之后的bean放入一级缓存
getSingleton会先从一级缓存中获取,一级缓存中没有才会从二级缓存中拿

结论: 二级缓存是为了解决并发场景下的循环依赖问题,将成熟bean和纯净bean分离开,避免读取到不完整的bean

问题: 第三级缓存的作用是什么? AOP或者是动态代理?
答: 二级缓存其实就可以解决AOP

准备动态代理相关配置

package com.sw.swtest.spring;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 16:51
 * @description :
 */
public class JdkDynamicProxy implements InvocationHandler {
    private Object target;

    public JdkDynamicProxy(Object target) {
        this.target = target;
    }

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("测试");
        return method.invoke(target,args);
    }
}

通过后置处理器的方式,解析切点的逻辑直接忽略了,这里只做了简单的模拟,只判断是不是InstanceA

package com.sw.swtest.spring;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 16:49
 * @description :
 */
@Component
public class JdkProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {

    @Override
    public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
        // 假设A被切点命中 需要创建代理
        if(bean instanceof InstanceA) {
            JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(bean);
            return  jdkDynamicProxy.getProxy();
        }
        return bean;
    }
}

面试: Spring的getBean在什么时候创建动态代理?
答: 如果没有发生循环依赖,Spring会在初始化之后创建动态代理,但是如果发生循环依赖,Spring会在实例化之后就创建动态代理

package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
        InstanceA instanceA = (InstanceA) getBean("instanceA");
        System.out.println(instanceA);
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {

        //给循环依赖添加出口
        Object singleton = getSingleton(beanName);
        if(singleton!= null){
            return singleton;
        }


        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();

        //创建动态代理(Spring里面是后置处理器的方式)
        instanceBean = new JdkProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);

        //添加到二级缓存
        earlySingletonObjects.put(beanName, instanceBean);

        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)

        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        return instanceBean;
    }


    public static Object getSingleton(String beanName){
        //先从一级缓存中拿
        if(singletonObjects.containsKey(beanName)){
           return singletonObjects.get(beanName);
           //一级缓存拿不到从二级缓存中拿
        }else if (earlySingletonObjects.containsKey(beanName)){
            return earlySingletonObjects.get(beanName);
        }
        return null;
    }

}

其实利用二级缓存就已经解决动态代理的问题了,但是这种写法会导致普通bean哪怕没有出现循环依赖,也会在实例化之后就创建了动态代理, Spring还是希望正常的bean能在初始化之后创建动态代理,只在出现循环依赖的时候才会在实例化之后创建动态代理

问题: 如何判断当前是不是循环依赖?
答: 二级缓存中只要存在该bean,就出现循环依赖(仔细品味)

在getSinleton()方法中,如果二级缓存中有值,那么就代表出现循环依赖

package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
        InstanceA instanceA = (InstanceA) getBean("instanceA");
        System.out.println(instanceA);
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {

        //给循环依赖添加出口
        Object singleton = getSingleton(beanName);
        if(singleton!= null){
            return singleton;
        }


        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();

        //添加到二级缓存
        earlySingletonObjects.put(beanName, instanceBean);

        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)

        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        return instanceBean;
    }


    public static Object getSingleton(String beanName){
        //先从一级缓存中拿
        if(singletonObjects.containsKey(beanName)){
           return singletonObjects.get(beanName);
           //一级缓存拿不到从二级缓存中拿
        }else if (earlySingletonObjects.containsKey(beanName)){
            //代表出现循环依赖
            //创建动态代理(Spring里面是后置处理器的方式)
            Object obj = new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName), beanName);
            //再放到二级缓存中去
            earlySingletonObjects.put(beanName,obj);
            return earlySingletonObjects.get(beanName);
        }
        return null;
    }

}

Spring中创建动态代理是在后置处理器中实现的,是不建议直接放在getBean()里面实现的,所以引入了三级缓存 singletonFactories.

所以:
1.AOP的代码可以继续放在实例化之后,添加二级缓存之前, 但是这样需要用函数式接口的钩子方法来实现,所以三级缓存map里存的其实就是函数式接口
2.如果某个bean实例需要动态代理,那么二级缓存里存原实例的bean还是动态代理呢?肯定是动态代理吧, 那存入二级缓存这一步就必须在动态代理之后,所以放在getSingleton()函数式接口回调完成,拿到动态代理之后
3.getSingleton()里判断如果发生循环依赖,那么就需要借助二级缓存来获取纯净bean,所以就需要从二级缓存中去获取
4.getSingleton() 需要先从一级缓存中获取bean,如果拿不到,需要从二级缓存中获取bean,如果拿不到,再从三级缓存中获取bean,获取到以后放入二级缓存
5.本来可以在实例化之后直接放入二级缓存,所以可以通过二级缓存中是否存在bean实例判断是否发生循环依赖的, 但是现在, 因为二级缓存的put是在动态代理之后,getSingleton()之中, 所以就没办法通过二级缓存来判断是否发生循环依赖, 所以引入了正在创建的标识singletonsCurrentlyInCreation

结论1: 一二级缓存就已经解决了AOP动态代理问题,所以引入三级缓存的目的是为了一种规范,为了解耦代码, 三级缓存解决了循环依赖,但是不是为了解决循环依赖而存在的

结论2: getBean(A) —> getSingleton(A)–> 一级缓存没有 && 没有正在创建beanA —> 标记正在创建A—>A的函数式接口放入三级缓存—>实例化A —> 属性赋值beanB—>getBean(B)—>getSingleton(B)—>一级缓存没有&&没有正在创建beanB —> 标记正在创建B —>B的函数式接口放入三级缓存 —> 实例化B —>属性赋值beanA—>getBean(A) —> 一级缓存没有 && 正在创建beanA —> 二级缓存没有—>A三级缓存判断存在 —>创建动态代理 —>代理A放入二级缓存 —>初始化A —> 二级缓存存在代理A,将代理A放入一级缓存 —> 初始化B --> 将B放入一级缓存

package com.sw.swtest.spring;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;

import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MissHeaven
 * @version : 1.0
 * @date : 2023/1/9 14:15
 * @description : Spring解决循环依赖(三级缓存)模拟
 */
public class MainStart {

    private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

    //一级缓存
    public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();
    //二级缓存 (将纯熟bean和纯净bean分离,避免读取到不完整的bean)
    public static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
    //三级缓存
    public static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();
    //循环依赖标识
    public static Set<String> singletonsCurrentlyInCreation = new HashSet<>();

    /**
     * 读取bean定义,在Spring中肯定是根据配置动态扫描的
     */
    public static void loadBeanDefinition() {
        RootBeanDefinition aBeanDefinition = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition bBeanDefinition = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", aBeanDefinition);
        beanDefinitionMap.put("instanceB", bBeanDefinition);
    }

    public static void main(String[] args) throws Exception {
        //加载beanDefinition
        loadBeanDefinition();

        //Spring中会 注册bean的后置处理器 registerBeanPostProcessors

        //循环创建bean
        for (String key : beanDefinitionMap.keySet()) {
            //会先创建A
            getBean(key);
        }
        InstanceA instanceA = (InstanceA) getBean("instanceA");
        System.out.println(instanceA);
    }

    //获取bean
    private static Object getBean(String beanName) throws Exception {

        //给循环依赖添加出口
        Object singleton = getSingleton(beanName);
        if(singleton!= null){
            return singleton;
        }

        //标记正在创建
        if(!singletonsCurrentlyInCreation.contains(beanName)){
            singletonsCurrentlyInCreation.add(beanName);
        }

        //实例化
        RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = beanDefinition.getBeanClass();
        //通过无参构造函数实例化(Spring中可以通过工厂或者有参构造函数)
        Object instanceBean = beanClass.newInstance();

        //放入三级缓存,创建动态代理(Spring里面是后置处理器的方式)
        Object finalInstanceBean = instanceBean;
        singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(finalInstanceBean, beanName));

        //属性赋值
        //先拿到所有的属性值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //找到属性值上有@Autowired注解的属性
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            if (annotation != null) {
                //打开私有属性的访问权限
                declaredField.setAccessible(true);
                //instanceB (Spring中除了byName, 还可以byType, byConstruct)
                String name = declaredField.getName();
                Object fieldObject = getBean(name);
                //Field将指定对象参数上此对象表示的字段设置为指定的新值
                declaredField.set(instanceBean, fieldObject);
            }
        }

        //初始化(init-method等等,三种配置方式,循环依赖的案例暂时忽略初始化方法)


        //由于递归完后,A还是原实例,所以需要从二级缓存中拿代理放入一级缓存,来保证代理在bean容器中生效
        if(earlySingletonObjects.containsKey(beanName)){
            instanceBean=earlySingletonObjects.get(beanName);
        }

        //添加到一级缓存
        singletonObjects.put(beanName, instanceBean);

        //移除二级缓存和三级缓存

        return instanceBean;
    }


    public static Object getSingleton(String beanName){
        //先从一级缓存中拿
        Object bean = singletonObjects.get(beanName);
        //如果一级缓存中没有,且正在创建,出现循环依赖
        if(bean == null && singletonsCurrentlyInCreation.contains(beanName)){
            //从二级缓存中拿
            bean = earlySingletonObjects.get(beanName);
            if(bean == null){
                //如果二级缓存中没有则从三级缓存中拿
                ObjectFactory factory = singletonFactories.get(beanName);
                if(factory != null){
                    //回调钩子方法,拿到动态代理
                    bean = factory.getObject();
                    earlySingletonObjects.put(beanName,bean);
                }
            }
        }
        return bean;
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值