IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Spring容器如何解决循环依赖的原理,2021最新Java框架体系架构面试题 -> 正文阅读

[Java知识库]Spring容器如何解决循环依赖的原理,2021最新Java框架体系架构面试题

2.1 一级缓存使用的map: private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);

2.2 二级缓存使用的map: private final Map<String, Object> earlySingletonObjects = new HashMap(16);

2.3 三级缓存使用的map:?private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);

3、Spring容器解决循环依赖简洁概述主要有四大流程方法:获取对象 getSingleton()、?创建对象(实例化) doCreateBean()、填充属性(初始化) populateBean()、返回对象 addSingleton()

在系统启动获取配置文件后,程序是依次读取并加载的,所以上面配置文件代码,先实例化a对象,然后初始化a对象给a添加b属性,再实例化b对象,最后初始化b对象给添加属性a.

那么在代码执行过程中,先调用getSingleton()方法,我们查看源码

@Nullable
    public Object getSingleton(String beanName) {           // 调用下方重载方法
        return this.getSingleton(beanName, true);
    }

    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference) {       // 先从一级缓存中获取a对象的实例
        Object singletonObject = this.singletonObjects.get(beanName);           // 如果从一级缓存中获取不到a对象,那么检查该对象是否正在被创建,如果正在被创建,则进入if循环中
        if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
            synchronized(this.singletonObjects) {            // 从二级缓存中获取该对象
                singletonObject = this.earlySingletonObjects.get(beanName);                   // 如果二级缓存中无法获取该对象,那么一定会进入如下if方法,因为allowEarlyReference传过来的时候就是true
                if (singletonObject == null && allowEarlyReference) {              // 从三级缓存中获取该对象
                    ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
                    if (singletonFactory != null) {                           // 如果获取到了该对象,就将三级缓存中的对象放到二级缓存中,并且将三级缓存中的对象删除
                        singletonObject = singletonFactory.getObject();
                        this.earlySingletonObjects.put(beanName, singletonObject);
                        this.singletonFactories.remove(beanName);
                    }
                }
            }
        }

        return singletonObject;
    }

从三面的源码发现,如果a第一次获取,那么第9行的if语句为false,将直接放回为null,这时回到创建对象doCreateBean()方法,该方法使用反射的方式生成a对象,并且该对象在三级缓存中,对象生成后就需要对a对象进行属性填充:

1 protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
 2         // 省略多行代码,大致就是调用各种方法,通过反射创建对象
 3         try {
 4             // a对象创建完成,调用属性填充方法,对a进行属性填充
 5             this.populateBean(beanName, mbd, instanceWrapper);
 6             exposedObject = this.initializeBean(beanName, exposedObject, mbd);
 7         } catch (Throwable var18) {
 8             if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
 9                 throw (BeanCreationException)var18;
10             }
11 
12             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18);
13         }
14 
15         if (earlySingletonExposure) {
16             Object earlySingletonReference = this.getSingleton(beanName, false);
17             if (earlySingletonReference != null) {
18                 // 省略多行代码
19             }
20         }
22         // 省略多行代码
23     }

在上面代码**doCreateBean()方法中先创建a对象,创建完成后会调用this.populateBean(beanName, mbd, instanceWrapper)**方法对a进行属性填出,这个时候会获取配置文件中所有里面的所有属性,发现会存在一个b属性,下面贴出部分源码

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
        if (bw == null) {
            if (mbd.hasPropertyValues()) {
                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
            }
        } else {
            boolean continueWithPropertyPopulation = true;
            if (!mbd.isSynthetic() && this.hasInstantiationAwareBeanPostProcessors()) {
                // 删除大量代码
            }

            if (continueWithPropertyPopulation) {
                // 删除大量源代码,applyPropertyValues方法中beanName为a,pvs为状态各种属性的PropertyValues对象,pvs就装有b这个属性
                if (pvs != null) {
                    this.applyPropertyValues(beanName, mbd, bw, (PropertyValues)pvs);
                }

            }
        }
    }

继续跟进applyPropertyValues方法的源码

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
        if (!pvs.isEmpty()) {
            if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
                ((BeanWrapperImpl)bw).setSecurityContext(this.getAccessControlContext());
            }
            MutablePropertyValues mpvs = null;
            List original;
            if (pvs instanceof MutablePropertyValues) {
                // 省略大量代码
            } else {
                original = Arrays.asList(pvs.getPropertyValues());
            }
            // 省略大量代码 大致过程是将属性对象pvs 转化成original List对象,然后在使用迭代器在下面进行迭代
            Iterator var11 = original.iterator();
            while(true) {
                while(var11.hasNext()) {
                    PropertyValue pv = (PropertyValue)var11.next();
                    if (pv.isConverted()) {
                        deepCopy.add(pv);
                    } else {
                        String propertyName = pv.getName();
                        Object originalValue = pv.getValue();
                        // 通过下面方法解决依赖的b,整个方法在迭代器中,外层在while(true)中,可能有多个属性,循环直到所有属性都解决了就return;或者抛出异常
                        Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
                        // 省略大量代码
                    }
                }

                if (mpvs != null && !resolveNecessary) {
                    mpvs.setConverted();
                }

                try {
                    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
                    return;
                } catch (BeansException var19) {
                    throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", var19);
                }
            }
        }
    }

继续跟进上面红色方法

public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
        if (value instanceof RuntimeBeanReference) {
            RuntimeBeanReference ref = (RuntimeBeanReference)value;
            return this.resolveReference(argName, ref);
        } else if (value instanceof RuntimeBeanNameReference) {
            // 省略多行代码
        }
        // 省略多行代码
    }

继续跟进红色部分的代码

private Object resolveReference(Object argName, RuntimeBeanReference ref) {
        try {
            String refName = ref.getBeanName();
            refName = String.valueOf(this.doEvaluate(refName));
            Object bean;
            if (ref.isToParent()) {
                // 省略多行代码


# 2021年Java中高级面试必备知识点总结

在这个部分总结了2019年到目前为止Java常见面试问题,取其面试核心编写成这份文档笔记,从中分析面试官的心理,摸清面试官的“套路”,可以说搞定90%以上的Java中高级面试没一点难度。

本节总结的内容涵盖了:消息队列、Redis缓存、分库分表、读写分离、设计高并发系统、分布式系统、高可用系统、SpringCloud微服务架构等一系列互联网主流高级技术的知识点。

**目录:**

![](https://img-blog.csdnimg.cn/img_convert/0c30527fdc017963a02fb4d16fa89004.png)

(上述只是一个整体目录大纲,每个点里面都有如下所示的详细内容,从面试问题——分析面试官心理——剖析面试题——完美解答的一个过程)

![](https://img-blog.csdnimg.cn/img_convert/04c4f634ef500aca2280da5333c47967.png)

**部分内容:**

![](https://img-blog.csdnimg.cn/img_convert/4a1266bce58f54a47fa929c6f835039b.png)

![](https://img-blog.csdnimg.cn/img_convert/ce6f828b3c246ccf2bd656233458bdc2.png)

![](https://img-blog.csdnimg.cn/img_convert/7bd9e893bb983bada2e50d37b3fb1754.png)



对于每一个做技术的来说,学习是不能停止的,小编把2019年到目前为止Java的核心知识提炼出来了,无论你现在是处于什么阶段,如你所见,这份文档的内容无论是对于你找面试工作还是提升技术广度深度都是完美的。

不想被后浪淘汰的话,赶紧搞起来吧,**高清完整版一共是888页,需要的话可以点赞+关注后,[点击这里免费获取](https://codechina.csdn.net/m0_60958482/java-p7)!**

为止Java的核心知识提炼出来了,无论你现在是处于什么阶段,如你所见,这份文档的内容无论是对于你找面试工作还是提升技术广度深度都是完美的。

不想被后浪淘汰的话,赶紧搞起来吧,**高清完整版一共是888页,需要的话可以点赞+关注后,[点击这里免费获取](https://codechina.csdn.net/m0_60958482/java-p7)!**

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-28 21:57:04  更:2021-08-28 21:57:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:05:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码