• 循环依赖的学习


    导言

    在gitee上搜索了一下,循环依赖的解决方式,正好看到有人手写了一个循环依赖,就顺便学习了一下。记录如下。

    地址:https://gitee.com/jackdawl/spring-circledependency.git

    什么是循环依赖

    循环依赖就是在a的类中注入b,在b的类中注入a.此时spring先读取a,然后读取a中的b属性。在b中又发现了a的属性。此时就会进入无限循环

    项目结构

    前置准备

    pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.jackdawl</groupId>
        <artifactId>spring-circledependency</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <maven.compiler.source>8</maven.compiler.source>
            <maven.compiler.target>8</maven.compiler.target>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.2.8.RELEASE</version>
            </dependency>
        </dependencies>
    
    </project>

    定义Iservice

    package com.jackdawl;
    
    public interface IService {
    
        void test();
    }

    定义OrderService

    package com.jackdawl;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class OrderService {
    
        @Autowired
        private IService userService;
    
        public OrderService(){
            System.out.println("实例化 OrderService");
        }
    
    
    }

    定义UserService

    package com.jackdawl;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class UserService implements IService{
        @Autowired
        private OrderService orderService;
    
        public UserService(){
            System.out.println("实例化 UserService");
        }
    
        @Override
        public void test() {
            System.out.println("实现类:UserService");
        }
    }

    循环依赖的测试

    package com.jackdawl;
    
    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.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 模拟循环依赖
     */
    public class MainClass1 {
    
        public static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        //一级缓存
        public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
        //模拟注册BeanDefinition
        public static void loadBeanDefinitionMap() {
            BeanDefinition bd1 = new RootBeanDefinition(UserService.class);
            BeanDefinition bd2 = new RootBeanDefinition(OrderService.class);
            beanDefinitionMap.put("userService", bd1);
            beanDefinitionMap.put("orderService", bd2);
        }
    
        public static void main(String[] args) {
            loadBeanDefinitionMap();
            beanDefinitionMap.forEach((beanName, beanDefinition) -> {
                try {
                    Object bean = getBean(beanName);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    
        public static Object getBean(String beanName) throws Exception {
            //创建bean
            RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
            Class<?> beanClass = beanDefinition.getBeanClass();
            Object instanceBean = beanClass.newInstance();
    
            //填充属性
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field f : declaredFields) {
                Autowired autowired = f.getAnnotation(Autowired.class);
                if (autowired != null) {
                    //从Spring 获取依赖对象
                    Object object = getBean(f.getName());
                    f.set(instanceBean, object);
                }
            }
    
            //初始化 略
    
            //添加到单例池
            singletonObjects.put(beanName, instanceBean);
    
            return instanceBean;
        }
    
    }

    执行代码

     发现一直在交替打印,符合上面讲的无限循环,直到堆栈异常

    那么怎么解决呢?

    /**
     * 解决循环依赖
     * 实例化后就加入到单例池
     * getBean 先从单例池拿,没有在去创建
     */

    解决循环依赖的第一种方式

    package com.jackdawl;
    
    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.Map;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 解决循环依赖
     * 实例化后就加入到单例池
     * getBean 先从单例池拿,没有在去创建
     */
    public class MainClass2 {
    
        public static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        //一级缓存
        public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    
        //模拟注册BeanDefinition
        public static void loadBeanDefinitionMap() {
            BeanDefinition bd1 = new RootBeanDefinition(UserService.class);
            BeanDefinition bd2 = new RootBeanDefinition(OrderService.class);
            beanDefinitionMap.put("userService", bd1);
            beanDefinitionMap.put("orderService", bd2);
        }
    
        public static void main(String[] args) {
            loadBeanDefinitionMap();
            beanDefinitionMap.forEach((beanName, beanDefinition) -> {
                try {
                    Object bean = getBean(beanName);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    
        public static Object getBean(String beanName) throws Exception {
            Object instanceBean = getSingleton(beanName);
            if (instanceBean != null){
                return instanceBean;
            }
            //创建bean
            RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
            Class<?> beanClass = beanDefinition.getBeanClass();
            instanceBean = beanClass.newInstance();
            //添加到单例池
            singletonObjects.put(beanName, instanceBean);
    
            //填充属性
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field f : declaredFields) {
                Autowired autowired = f.getAnnotation(Autowired.class);
                if (autowired != null) {
                    //禁用安全检查,私有属性,保证可见;不禁用会报错
                    f.setAccessible(true);
                    //从Spring 获取依赖对象
                    Object object = getBean(f.getName());
                    f.set(instanceBean, object);
                }
            }
    
            //初始化 略
    
    
            return instanceBean;
        }
    
        public static Object getSingleton(String beanName){
            if (singletonObjects.containsKey(beanName)){
                return singletonObjects.get(beanName);
            }
            return null;
    
        }
    
    }

    执行结果

     看看是怎么执行的

    首先进入的是userService,如果不存在就会添加进入到一级缓存中

    然后读取属性发现到了orderservice,获取依赖对象,需要循环获得

     

    orderservice从一级缓存中也是获取不到的,所以也是走添加到单例池的操作。然后在它的属性中也发现了userService,继续循环

     

    此时从一级缓存中是可以获得userService的。直接返回。

     

    返回的过程中发现当前的类还是orderservice的。所以还是先实例化orderservice里面的userservice,然后再实例化orderservice

     

     

    orderservice实例化完成就会重新进入回到userservice中,最终实例化userservice

     执行流程为

    userservice->userservice.orderservice->orderservice.userservice->orderservice->userservice

     spring是怎么实现这个功能的呢?

    定义JdkDynamicProxy 

    package com.jackdawl;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    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("进入动态代理 invoke 方法");
            return method.invoke(target,args);
        }
    }

    定义MyProxyBeanPostProcessor

    package com.jackdawl;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.SmartInstantiationAwareBeanPostProcessor;
    
    public class MyProxyBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor {
    
        @Override
        public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
    
            // 模拟 UserService 需要创建代理
            if(bean instanceof UserService) {
                JdkDynamicProxy jdkDynamicProxy = new JdkDynamicProxy(bean);
                return  jdkDynamicProxy.getProxy();
            }
            //不需要创建代理的直接返回原始bean
            return bean;
        }
    }

    test

    package com.jackdawl;
    
    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.management.BufferPoolMXBean;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Map;
    import java.util.Set;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * 解决循环依赖
     * 实例化后就加入到单例池
     * getBean 先从单例池拿,没有在去创建
     * 如果 userService 需要创建动态代理,最后放入单例池中的对象是代理对象,但是在 orderService 注入的对象是原始对象,这就产生了冲突。
     * 所以要标记发生循环依赖时,orderService 能拿到 userService 的原始对象或者原始对象的代理
     * 具体拿到哪种对象的逻辑封装到一个函数接口中,添加到三级缓存
     * 正在创建的bean的 beanName 都放到一个集合中,集合中能查到表明发生循环依赖,
     * 此时去缓存中拿对象,一二级都没有,就由三级缓存函数接口返回对象放入二级缓存,
     * 便于多个对象依赖 userService 时,单例池拿不到直接从二级缓存获取
     * 如果 userService 需要AOP创建代理,需要判断
     */
    public class MainClass3 {
    
        public static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
        //一级缓存
        public static Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        //二级缓存
        public static Map<String, Object> earlySingletonObjects = new HashMap<>(16);
        //三级缓存
        public static Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
    
        //创建过代理对象的原始对象 beanName-bean
        private final Map<Object, Object> earlyProxyReferences = new ConcurrentHashMap<>(16);
    
        //正在创建的bean的bean名称
        public static Set<String> singletonCurrentlyInCreation = new HashSet<>();
    
        //模拟注册BeanDefinition
        public static void loadBeanDefinitionMap() {
            BeanDefinition bd1 = new RootBeanDefinition(UserService.class);
            BeanDefinition bd2 = new RootBeanDefinition(OrderService.class);
            beanDefinitionMap.put("userService", bd1);
            beanDefinitionMap.put("orderService", bd2);
        }
    
        public static void main(String[] args) {
            loadBeanDefinitionMap();
            beanDefinitionMap.forEach((beanName, beanDefinition) -> {
                try {
                    Object bean = getBean(beanName);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
    
        public static Object getBean(String beanName) throws Exception {
            Object instanceBean;
            instanceBean = getSingleton(beanName);
            if (instanceBean != null) {
                return instanceBean;
            }
    
            //创建bean
            RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
            Class<?> beanClass = beanDefinition.getBeanClass();
            instanceBean = beanClass.newInstance();
            final Object bean = instanceBean;
            singletonCurrentlyInCreation.add(beanName);
            singletonFactories.put(beanName, () -> new MyProxyBeanPostProcessor().getEarlyBeanReference(bean, beanName));
    
            //填充属性
            Field[] declaredFields = beanClass.getDeclaredFields();
            for (Field f : declaredFields) {
                Autowired autowired = f.getAnnotation(Autowired.class);
                if (autowired != null) {
                    //禁用安全检查,私有属性,保证可见;不禁用会报错
                    f.setAccessible(true);
                    //从Spring 获取依赖对象
                    Object object = getBean(f.getName());
                    f.set(instanceBean, object);
                }
            }
    
            //初始化 略
    
            //模拟需要AOP则从二级缓存拿代理对象
            if (earlySingletonObjects.containsKey(beanName)){
                instanceBean = earlySingletonObjects.get(beanName);
                singletonObjects.put(beanName, instanceBean);
            }else {
                singletonObjects.put(beanName, instanceBean);
            }
    
            //删除二三级缓存,删除创建中集合beanName
            singletonFactories.remove(beanName);
            earlySingletonObjects.remove(beanName);
            singletonCurrentlyInCreation.remove(beanName);
    
    
            return instanceBean;
        }
    
        public static Object getSingleton(String beanName) {
            //c从单例池拿
            Object instanceBean = singletonObjects.get(beanName);
            //单例池没拿到对象,而且发生循环依赖就从二级缓存拿
            if (instanceBean == null && singletonCurrentlyInCreation.contains(beanName)) {
                instanceBean = earlySingletonObjects.get(beanName);
                if (instanceBean == null) {
                    //二级缓存拿不到对象就从三级缓存拿
                    ObjectFactory<?> objectFactory = singletonFactories.get(beanName);
                    if (objectFactory != null) {
                        instanceBean = objectFactory.getObject();
                        earlySingletonObjects.put(beanName, instanceBean);
                        singletonFactories.remove(beanName);
                    }
                }
            }
            return instanceBean;
    
        }
    
    }

    打断点看看

    首先是userService

     单例池为空,正在创建的bean名称为空,直接返回null

     加入正在创建的bean,加入三级缓存中。读取属性orderservice

     进入orderservice

     orderservice也是直接返回

     又会进入userservice

     

    此时一级缓存没有,正在创建的bean有,从二级缓存中拿,二级缓存没有,从三级缓存中拿,拿出来,加入二级缓存,删除三级缓存

     

     然后直接返回userservice

     接着回到orderservice

     二级缓存中没有orderservice,直接加入一级缓存中,然后删除三级缓存,二级缓存以及正在创建的dean

    测试结果

  • 相关阅读:
    Splunk_转发器配置_AD
    Splunk SPL 时间转换
    Splunk_索引自动清理历史数据
    Python 备查 线程池
    Splunk_SPL 排除搜索结果
    Splunk_SPL 查询时间范围
    质量的分级
    各类BOM
    Jmeter负载测试的注意事项
    MEM的面试记录
  • 原文地址:https://www.cnblogs.com/cj8357475/p/16418983.html
Copyright © 2020-2023  润新知