当前位置: 首页 > 网络应用技术

春季求解循环依赖性如何写得很好

时间:2023-03-08 20:52:17 网络应用技术

  Java的开发通常不在春季左右,因此肯定会询问春季相关内容的面试,并且循环依赖性在春季将是很高的频率面部测试问题。

  不久前,我的一个朋友去接受采访,并被问及周期的依赖。结果,他仍然很小。他们的聊天过程如下。

  访调员:说什么是循环依赖性

  朋友:两个或多个对象彼此依赖,最后形成一个封闭的循环。例如,一个对象A依赖于B对象,而B对象也取决于对象A对象A

  访调员:有什么问题?

  朋友:对象的创建过程将产生一个死周期,类似于以下

  访调员:春季是如何解决的?

  朋友:它是由第三级高速缓存暴露对象提前解决的

  访调员:第三级缓存中存储的内容分别存储

  朋友:第一个级别的缓存是完成的产品对象,所有实例和初始化均已完成。我们应用程序中使用的对象是第一个级别的缓存

  次要缓存是半生产的产品,用于在对象创建过程中解决循环依赖问题

  objectFactory存储在第三级高速缓存中 键入lambda表达式,用于处理

  访调员:为什么使用第三级缓存来解决循环依赖性问题(只有第一个级别的缓存不好,只有第二个级别的缓存无效)

  朋友:只能通过第一个级别的缓存来解决,但会使整个逻辑复杂化

  半生产对象不能直接使用(存在NPE问题),因此Spring需要确保在启动过程中,中间产生的所有半生成对象最终将成为完成的对象

  如果在第一个级别的缓存中混合了半生成对象和成品对象,则为了区分它们,它必然会增加一些标签和逻辑处理,这将导致对象创建过程的复杂性。

  将半生成对象与成品对象分开,并且两个级别的缓存应具有其职责,这可以简化对象的对象的过程,这更简单,直观。

  如果弹簧不引入AOP,那么两个级别的缓存就足够了,但是作为春季的核心之一,AOP怎么会更少?

  因此,为了处理AOP的周期依赖性,Spring引入了第三个级别的缓存,以处理循环依赖项时处理代理对象的创建

  访调员:如果代理对象的创建过程已提前提出,然后进行实例化,并且在初始化之前,它只能使用两个级别来缓存?

  朋友想:这是我所知的盲点,我做到了!但是点了点头:您说的是有道理的,我没有考虑过,我回去更改源代码并尝试

  问一些以前的问题,我觉得我的朋友回答得很好,但是最后一个问题中的第三级缓存仍然很糟糕,以至于答案是如此丢失。损失是什么?

  在讲座的正式开幕之前,让我们首先回顾一些内容,否则后来的内容可能有点盲目(实际上,主要是害怕您)

  1.对象的创建

  一般而言,对象的创建分为两个步骤:实例化,初始化,实例化是指从堆中应用内存空间,JVM级别的对象的创建以及初始化是指属性的分配属性值的值。

  当然,它也可以用来通过构造函数完成实例和初始化以实现对象的创建

  当然还有其他方法,例如工厂等。

  2.弹簧注入方法

  有三种类型:建设性方法注入,二阶方法注入,接口注入

  界面注入过于灵活的方式和易用性较差,因此不广泛使用。每个人都知道有这样的说法。不要仔细地扣除。

  注入构造方法的方法是实例并初始化并完成它。它可以快速创建可以直接使用的对象,但无法处理循环依赖性问题。只是了解它。

  Setter方法注入的方法是通过反映对象的对象来反映对象的设置方法来完成属性的分配。

  3.弹簧3级缓存的顺序

  第三级缓存的顺序来自查询,这与类中的定义顺序无关。

  因此,第一个 - 级别的缓存:单元观察者,第二个级别的缓存:早期的singletonobjects,第三个缓存:singletonFactories

  4.解决这个想法

  除了春天,让我们自己实施它,我们将如何处理循环依赖性问题?

  尽管半生产产品不能直接在应用程序中使用,但仍然可以在对象的过程中使用,就像这样

  有一个堆栈,有堆栈而不是输入堆栈,它解决了循环依赖性的死周期问题。

  春天也是这样实施的吗?基于5.2.12.Release,让我们看一下春季如何解决周期依赖性

  源代码跟踪将从下面的几个不同情况进行。如果中间有问题,请先使用笔记,并且在阅读所有内容后,仍然有问题,请在评论区域留言。

  推荐春季靴基本教程和实际战斗示例:https://github.com/javastacks/spring-boot-practice

  1.没有依赖,有AOP

  该代码非常简单:春季非依赖性

  https://gitee..com/youzhibing/spring-circle/tree/master/spring-no-depernncence

  目前,SimpleBean对象是如何在春季创建的?让我们一起遵循源代码

  接下来,我们开始调试

  无法跟进,或者如果您快速跳过,我们可以首先跳过它,专注于遵循方法和停留的代码的方法。目前,属性值有几个内容。

  让我们跟随CreateBean Down

  关键代码是在docreatebean中,几种关键方法的呼吁值得每个人遵循

  此时:代理对象的创建由对象实例完成,并且初始化也已完成。

  因此,在这种情况下:只有第一个级别的缓存就足够了,其他两个缓存不能是

  2.循环依赖,没有AOP

  代码仍然很简单:弹簧圈简单

  https://gitee..com/youzhibing/spring-circle/tree/master/spring-circle-simple-simple

  此时依赖周期的两个类别是:圆圈和循环

  对象的创建过程基本上与上一个相同,但是周期依赖性越来越少,因此我们关注:populeatebean和initializebean方法

  第一个创建是圆对象,然后我们从创建其人群开始,在开始之前,让我们看一下第三级缓存中的数据情况

  我们开始使用PopulateBean发布,该群体完成了属性的填充,并且与循环依赖关系有关。我们必须仔细观察并关注

  填充圆对象的属性时,请转到弹簧容器以找到循环对象,并发现它是创建的。

  目前,第三级高速缓存中的数据尚未更改,但是SetSingletonScrressineCreation中有更多循环

  我相信这里没有问题,我们继续看不起

  实例化循环后,填写其属性圆圈,转到弹簧以获取圆对象,然后来到熟悉的dogetbean

  目前,第一个或第二个缓存中没有圆圈和循环,并且三个缓存中有两个。然后,我们低头关注它。

  当通过getingleton获得圆时,在第三级缓存中调用了getearlybeanReference,但是由于没有AOP,getearlybeancence直接返回了普通的半限制产品圆

  然后将半生产的产品圆放入辅助缓存中,将其返回,然后将其填充到循环对象中

  目前,循环对象是成品。然后返回循环对象并将其填充到圆对象中,如下所示

  我们发现完成的循环直接放入第一个级别的缓存中。次要缓存从头开始没有循环

  此时,缓存中的数据,我相信每个人都可以想到

  尽管循环对象已填充在圆对象中,但仍存在丢失过程的过程。然后我们低头看

  将成品放置在第一个级别的缓存中,辅助缓存中的圆圈无需使用即可直接删除。在所有级别的缓存中的数据都很明确。

  在这种情况下,让我们回顾各个级别的缓存感。第一个级别的缓存的存在已满。可以说第二级缓存没有存在感。第三级缓存具有存在感(在循环中填充城市时很有用)

  因此,在这种情况下:它可以减少缓存,只有两个级别的缓存就足够了

  3.循环依赖 + AOP

  该代码仍然非常简单:弹簧循环,根据循环依赖性添加AOP

  与以前的情况相比,AOP更多。让我们看一下对象过程的差异。

  创建过程通常与以前的情况相同,但是差异的一小部分。当我来自源代码时,我将停止这些差异。其他人会跳过。每个人都应该仔细看一下。

  检查圆圈,然后填充半生产的产品圆属性循环,转到弹簧容器以获取循环对象,并发现没有

  然后实例化循环,然后填充半条环的属性,然后转到弹簧容器以获取圆对象

  此过程与以前的情况一致,并直接跳过。从上图中的红色步骤中,我们开始遵循源代码。目前,第三级缓存中的数据如下

  注意它,重要的地方在这里

  当我们发现获得第三级缓存时,我们称为getearlyBeanReference创建半生产产品圈代理对象对象

  将半生产产品圆的代理放在辅助缓存中,然后将代理对象返回到半生产产品循环的圆属性

  注意:目前,它是循环的初始化,但是半生产产品圆的代理是提前创建的

  循环的初始化尚未完成。

  半生产产品循环的初始化以初始化方法完成,并在末尾创建了循环成品的代理对象

  创建循环代理对象之后,将其放置在第一个级别的缓存中(在第三级缓存中删除循环,并且从第二个缓存的开始到末尾没有循环)

  然后将循环代理对象返回到半生产产品圆的属性,然后执行半生产产品圆

  由于已经生成了圆的代理对象(在第二个缓存中),因此不必成为代理对象。

  目前,缓存中各个级别的数据如下(普通圆对象和循环对象都在其各自代理的目标中)

  在这种情况下,让我们回顾各个级别的缓存的存在感。第一个级别的缓存仍然充满了存在,第二级缓存具有存在感,而第三级缓存具有存在感。

  第三级高速缓存会提前创建圆形代理对象。如果未提前创建,它只能分配循环对象的属性。

  第二级缓存用于存储圆形代理,并用于求解周期依赖性;在此示例中,依赖项更简单也许并不明显。

  第一个级别的缓存存储了暴露于外界的对象,这可能是代理对象或普通对象。

  因此,在这种情况下:没有人可以少于三个缓存之一

  4.循环依赖项 + AOP +删除第三级缓存

  没有依赖。对于AOP,我们知道在创建完成对象后创建了AOP代理的生成。这也是春季的设计原理。

  在循环依赖性 + aop的情况下,圆的代理对象的产生是先进的,因为必须保证它可以确保其AOP函数,但是仍然遵循循环代理对象的生成

  如果我们打破此原理并推进代理对象的逻辑,我们是否可以使用三个级别的缓存,而是只使用两个级别来缓存?

  代码仍然很简单:弹簧圈custom

  https://gitee..com/youzhibing/spring-circle/tree/master/spring-circle-custom

  这只是春季源代码的一个很小的变化。更改如下:

  删除第三个级别的缓存,然后提前提前代理对象的创建逻辑。实例化后,在初始化之前;让我们看执行结果

  没有问题。如果您有兴趣,则可以按照源代码进行操作。我相信每个人都掌握了以下过程。

  5.循环依赖 + AOP +注释

  目前,基于XML的配置越来越少,越来越多的配置基于注释,因此它还提供了注释版本的版本,供每个人遵循源代码

  该代码仍然很简单:弹簧循环宣布

  https://gitee..com/youzhibing/spring-circle/tree/master/spring-circle-annotion

  跟踪过程基本上与循环依赖关系 + AOP相同,但是属性的填充有一些差异。可以查看:春季自动装配→SAO Talk @Autowired的基本工作原理

  1.第三级缓存的作用是每个级别的

  第一个级别的缓存沉积了暴露于外界的对象,这是我们需要使用的

  第二级缓存的作用是处理周期依赖性对象的创建。存储了半生产对象或半生产对象的代理对象

  第三级缓存的函数具有创建AOP +循环依赖性对象的问题,该对象可以预先创建代理对象

  2.为什么春季引入第三级缓存

  严格来说,第三级缓存不是必不可少的,因为可以预先创建代理对象

  提前创建代理对象只会节省这样的投掷记忆空间,并且不会带来性能的改善,但它将破坏春季春季的设计原理

  春季的设计原则是确保尽可能多地完成普通对象的创建,并将其更新到其AOP代理(尽可能多地生成代理对象)

  因此,Spring使用第三级缓存,该缓存不仅维护了设计原理,而且还可以处理循环依赖性。它愿意接受这样的投掷记忆空间。

  作者:Qingshi Road

  链接:www.cnblogs.com/youzhibing/p/14337244.html