Spring


Spring

聊聊 Spring AOP 实现原理

Spring 实现 AOP 主要是通过动态代理,即在运行时去构建一个代理类去实现。Spring 实现动态代理有两种,分别是:JDK 动态代理、cglib 动态代理。

JDK 动态代理只能代理接口,其本质是通过反射的方式去实现。而 cglib 可以代理类和接口,其本质是通过 ASM 字节码生成库去生成代理类。

参考资料:

什么是 Spring IoC ?

控制反转,意思是之前是我们主动去创建对象,但现在我们将所有对象都丢给 Spring 管理。当我们需要某个对象的时候,通过注解或者配置文件的方式,让 Spring 容器帮我们将对象注入进来。

聊聊 Spring 的容器初始化过程?

如此一来,Spring 的容器初始化过程就显得非常重要了。Spring 容器初始化可以分为几个过程:

  1. 获取 bean 的真实名称
  2. 从缓存中获取 bean 实例
  3. 创建 bean 实例
  4. 适配转换 bean 实例

获取 bean 的真实名称。 我们传入的 bean 名可能是别名,所以我们需要去获取到真实的 bean 名称。

从缓存中获取 bean 实例。 Spring 容器会将 bean 放入缓存中,我们首先去缓存中获取数据,并根据获取到的缓存对象,去拿到真实的 bean 对象。

创建 bean 实例。 如果无法从缓存中获取到 bean 实例,那么就需要去实例化对象,其会根据 scope 去进行 bean 实例的初始化。首先先创建 bean,之后再进行初始化操作,包括后置处理器的处理。

适配转换 bean 实例。 就是根据传进来的参数,对获取到的 bean 进行类型转换,使其符合要求。

聊聊 Spring 是如何解决循环依赖的?

Spring 的循环依赖,是指 A 依赖 B,B 依赖 C,C 依赖 A,从而使得 ABC 之间形成一个依赖环。Spring 只能解决单例作用域的 setter 类型的循环依赖,无法解决构造器方式的循环依赖。

Spring 解决循环依赖的方法,可以简单概括为:初始化过程切分 + 三级缓存。

初始化过程切分。 原本我们实例化一个 bean 实例,都是直接创建,并将其初始化。但 Spring 将 bean 的初始化分成了 创建 bean 实例 + 初始化 bean 两个过程。当创建了一个 bean 实例后,提前将其放入三级缓存,从而使得其提前可被其他对象获取到,从而打破了循环依赖。

三级缓存。 指的是一级缓存 singletonObjects、二级缓存 earlySingletonObjects、三级缓存 singletonFactories。其中一级缓存存放的就是已经实例化完成的对象,二级缓存存放的是半成品,三级缓存存放的是刚刚创建的实例、还未进行初始化。

--- 以下是低频内容,不用记,大致理解下就好。 ---

当我们的 A 对象创建时,其会使用反射创建一个 A 对象工厂放入 singletonFactories,通过对象工厂便可获得一个 A 的早期对象。之后因为依赖 B 对象,又会将 B 放入 singletonFactories。之后因为依赖 C 对象,又会将 C 放入 singletonFactories。

其整体过程如下:

放入三级缓存

  • 获取 A 实例,将 A 的 ObjectFactory 放入 singletonFactories 中,在 populateBean 的地方,去获取 B 实例。
  • 获取 B 实例,将 B 的 ObjectFactory 放入 singletonFactories 中,在 populateBean 的地方,去获取 C 实例。
  • 获取 C 实例,将 B 的 ObjectFactory 放入 singletonFactories 中,在 populateBean 的地方,去获取 A 实例。

放入一二级缓存

  • 获取 A 实例,在 getSingleton 方法发现有三级缓存,于是从 getEarlyReference 方法获取早起引用。接着将 A 实例从三级缓存 singletonFactories 中删除,放入二级缓存 earlySingletonObjects 中。接着返回 A 实例给 C,C 获取到 A 实例后初始化完成,接着便将 C 放入一级缓存 singletonObjects 中,移除 C 在二三级缓存的值。 此时是在 beanName 为 c 的程序中,接着返回到 beanName 为 b 的程序中。
  • 在 beanName 为 b 的程序中。此时 C 对象初始化完成,可以获取到 C 对象(DefaultSingletonBeanRegistry.234行),于是 B 对象初始化完成,接着将 B 对象放入一级缓存 singletonObjects 中,移除 B 在二三级缓存的值。 接着返回到 beanName 为 a 的程序中。
  • 在 beanName 为 a 的程序中。此时 B 对象初始化完成,可以获取到 B 对象(DefaultSingletonBeanRegistry.234行),于是 A 对象初始化完成,接着将 A 对象放入一级缓存 singletonObjects 中,移除 A 在二三级缓存的值。 接着程序结束。
上次编辑于: 2022/7/30 09:07:48