Spring循环依赖-spring源码详解(四)

简介: Spring循环依赖-spring源码详解(四)
 public static void loadBeanDefinitions() {
        RootBeanDefinition rootBeanDefinitionA = new RootBeanDefinition(InstanceA.class);
        RootBeanDefinition rootBeanDefinitionB = new RootBeanDefinition(InstanceB.class);
        beanDefinitionMap.put("instanceA", rootBeanDefinitionA);
        beanDefinitionMap.put("instanceB", rootBeanDefinitionB);
    }

@Component
public class InstanceA {
    @Autowired
    private InstanceB instanceB;

    public InstanceB getInstanceB() {
        return instanceB;
    }

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

    public InstanceA(InstanceB instanceB) {
        this.instanceB = instanceB;
    }

    public InstanceA() {
        System.out.println("实例化A");
    }
}

首先把bean放入beanDefinition,之后,循环bean定义,通过bean的key来获取beanDefinition,

通过无参构造函数反射来获取class,再赋值属性。

        // 加载到beanDefinition
        loadBeanDefinitions();

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

    private static Map<String, Object> singletonObjects = new ConcurrentHashMap<>();

    public static Object getBean(String beanName) throws Exception {
        Object singleton = getSingleton(beanName);
        if(singleton != null){
            return singleton;
        }

        // 实例化
        RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
        Class<?> beanClass = rootBeanDefinition.getBeanClass();
        // 通过class 无参构造函数 实例化
        Object instanceBean = beanClass.newInstance();

        singletonObjects.put(beanName, instanceBean);
        // 属性赋值
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            Autowired annotation = declaredField.getAnnotation(Autowired.class);
            // 说明bean有autowired
            if (annotation != null) {
                // 打开访问权限
                declaredField.setAccessible(true);
                // byName  byType   拿到了 instanceB名字
                String name = declaredField.getName();
                // 拿到B的bean
                Object fileObject = getBean(name);
                declaredField.set(instanceBean, fileObject);
            }
        }
        // 初始化
        // 放入缓存
//        singletonObjects.put(beanName, instanceBean);
        return instanceBean;
    }

    private static Object getSingleton(String beanName) {
        Object singleton = singletonObjects.get(beanName);
        if (singleton != null) {
            return singleton;
        }
        return null;
    }

image.png

这样写完之后,就不会有死循环,但是没有用到二级缓存,二级缓存可以用来放半成品的bean,解决多线程的情况下,多个线程同时创建bean,防止其他线程拿到不完整的bean,于是 加上二级缓存来写。

   private static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();

   public static Object getBean(String beanName) throws Exception {
       Object singleton = getSingleton(beanName);
       if (singleton != null) {
           return singleton;
       }

       // 实例化
       RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
       Class<?> beanClass = rootBeanDefinition.getBeanClass();
       // 通过class 无参构造函数 实例化
       Object instanceBean = beanClass.newInstance();

       // 二级缓存
       earlySingletonObjects.put(beanName, instanceBean);
       // 属性赋值
       Field[] declaredFields = beanClass.getDeclaredFields();
       for (Field declaredField : declaredFields) {
           Autowired annotation = declaredField.getAnnotation(Autowired.class);
           // 说明bean有autowired
           if (annotation != null) {
               // 打开访问权限
               declaredField.setAccessible(true);
               // byName  byType   拿到了 instanceB名字
               String name = declaredField.getName();
               // 拿到B的bean
               Object fileObject = getBean(name);
               declaredField.set(instanceBean, fileObject);
           }
       }
       // 初始化
       // 放入缓存
       singletonObjects.put(beanName, instanceBean);
       return instanceBean;
   }

   private static Object getSingleton(String beanName) {
       Object singleton = singletonObjects.get(beanName);
       if (singleton != null) {
           return singleton;
       }
       Object earlySingleton = earlySingletonObjects.get(beanName);
       if (earlySingleton != null) {
           return earlySingleton;
       }
       return null;
   }

用解耦的方式,beanPostProcessor来创建动态代理。

如果在最后调用动态代理,这时候循环依赖的bean就不是动态代理的bean,所以要在之前就创建动态代理。所以这里有两个地方调用动态代理,实例化之后和初始化之后调用。

只在循环依赖的情况下在实例化之后创建动态代理,所以需要判断当前是不是循环依赖。
前面一级缓存中没拿到,而二级缓存中有,才是循环依赖。

而spring源码里有一行代码,用来判断是否是循环依赖,加了一个正在创建对象的标识。

   private static Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>();
   // 存放函数接口
   private static Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>();

   private static Set<String> singletonCurrennlyInCreation = new HashSet<>();

   public static Object getBean(String beanName) throws Exception {
       Object singleton = getSingleton(beanName);
       if (singleton != null) {
           return singleton;
       }

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

       // 实例化
       RootBeanDefinition rootBeanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
       Class<?> beanClass = rootBeanDefinition.getBeanClass();
       // 通过class 无参构造函数 实例化
       Object instanceBean = beanClass.newInstance();

       // 创建动态代理
       // 只在循环依赖的情况下在实例化之后创建动态代理
       //Object o = new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);
       /*singletonFactories.put(beanName, new ObjectFactory() {
           @Override
           public Object getObject() throws BeansException {
               return  new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean,beanName);
           }
       });*/
       singletonFactories.put(beanName, () -> new JDKProxyBeanPostProcessor().getEarlyBeanReference(instanceBean, beanName));

       // 二级缓存
       //earlySingletonObjects.put(beanName, instanceBean);
       // 属性赋值
       Field[] declaredFields = beanClass.getDeclaredFields();
       for (Field declaredField : declaredFields) {
           Autowired annotation = declaredField.getAnnotation(Autowired.class);
           // 说明bean有autowired
           if (annotation != null) {
               // 打开访问权限
               declaredField.setAccessible(true);
               // byName  byType   拿到了 instanceB名字
               String name = declaredField.getName();
               // 拿到B的bean
               Object fileObject = getBean(name);
               declaredField.set(instanceBean, fileObject);
           }
       }
       // 初始化


       /*if(earlySingletonObjects.containsKey(beanName)){
           instanceBean = earlySingletonObjects.get(beanName);
       }*/
       // 放入缓存
       singletonObjects.put(beanName, instanceBean);
       return instanceBean;
   }

   private static Object getSingleton(String beanName) {
     /*  Object singleton = singletonObjects.get(beanName);
       if (singleton != null) {
           return singleton;
       }
       Object earlySingleton = earlySingletonObjects.get(beanName);
       if (earlySingleton != null) {

           return earlySingleton;
       }
       return null;*/
       Object bean = singletonObjects.get(beanName);
       if (bean == null && singletonCurrennlyInCreation.contains(beanName)) {
           // 是循环依赖
           bean  = earlySingletonObjects.get(beanName);
           synchronized (singletonObjects){
               if(bean == null){
                   ObjectFactory objectFactory = singletonFactories.get(beanName);
                   if (objectFactory != null) {
                       // 钩子函数 去创建 aop代理
                       bean = objectFactory.getObject();
                       earlySingletonObjects.put(beanName, bean);
                       singletonFactories.remove(beanName);
                   }
                   return bean;
               }
           }
       }
       return bean;
   }

相关文章
|
2天前
|
人工智能 Java Spring
Spring Boot循环依赖的症状和解决方案
Spring Boot循环依赖的症状和解决方案
|
2天前
|
Java 应用服务中间件 Nacos
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
Spring Cloud 常用各个组件详解及实现原理(附加源码+实现逻辑图)
37 0
|
2天前
|
监控 数据可视化 安全
一套成熟的Spring Cloud智慧工地平台源码,自主版权,开箱即用
这是一套基于Spring Cloud的智慧工地管理平台源码,具备自主版权,易于使用。平台运用现代技术如物联网、大数据等改进工地管理,服务包括建设各方,提供人员、车辆、视频监控等七大维度的管理。特色在于可视化管理、智能报警、移动办公和分布计算存储。功能涵盖劳务实名制管理、智能考勤、视频监控AI识别、危大工程监控、环境监测、材料管理和进度管理等,实现工地安全、高效的智慧化管理。
|
2天前
|
监控 Java 应用服务中间件
Spring Boot 源码面试知识点
【5月更文挑战第12天】Spring Boot 是一个强大且广泛使用的框架,旨在简化 Spring 应用程序的开发过程。深入了解 Spring Boot 的源码,有助于开发者更好地使用和定制这个框架。以下是一些关键的知识点:
20 6
|
2天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
29 3
|
2天前
|
存储 前端开发 Java
Spring Boot自动装配的源码学习
【4月更文挑战第8天】Spring Boot自动装配是其核心机制之一,其设计目标是在应用程序启动时,自动配置所需的各种组件,使得应用程序的开发和部署变得更加简单和高效。下面是关于Spring Boot自动装配的源码学习知识点及实战。
16 1
|
2天前
|
缓存 Java 开发工具
【spring】如何解决循环依赖
【spring】如何解决循环依赖
14 0
|
2天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
103 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
2天前
|
设计模式 安全 Java
【初学者慎入】Spring源码中的16种设计模式实现
以上是威哥给大家整理了16种常见的设计模式在 Spring 源码中的运用,学习 Spring 源码成为了 Java 程序员的标配,你还知道Spring 中哪些源码中运用了设计模式,欢迎留言与威哥交流。
|
2天前
|
存储 缓存 Java
【Spring系列笔记】依赖注入,循环依赖以及三级缓存
依赖注入: 是指通过外部配置,将依赖关系注入到对象中。依赖注入有四种主要方式:构造器注入、setter方法注入、接口注入以及注解注入。其中注解注入在开发中最为常见,因为其使用便捷以及可维护性强;构造器注入为官方推荐,可注入不可变对象以及解决循环依赖问题。本文基于依赖注入方式引出循环依赖以及三层缓存的底层原理,以及代码的实现方式。
24 0