循环依赖的学习

导言

在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

 

测试结果

 

posted @ 2022-06-28 12:00  小陈子博客  阅读(73)  评论(0编辑  收藏  举报