Skip to content

Spring进阶- Spring IOC实现原理详解之Bean实例化(生命周期,循环依赖等) #32

Description

@cyjxiaozhi

本文主要研究如何从IOC容器已有的BeanDefinition信息,实例化出Bean对象;
这里还会包括三块重点内容:BeanFactory中getBean的主体思路
Spring如何解决循环依赖问题
Spring中Bean的生命周期

一、BeanFactory中getBean的主体思路
在 Spring 框架中,BeanFactory 是最基本的容器接口,用于获取 Spring 管理的 Bean 对象。它的 getBean 方法是用来获取容器中定义的 Bean 的核心方法。

getBean 方法的主体思路

BeanFactory 的 getBean 方法的大致执行流程如下:
1. 检查缓存:
• getBean 方法首先会检查指定的 Bean 是否已经存在于缓存(或称作单例池)中。
• 如果该 Bean 已经实例化并且是单例模式,它会直接返回缓存中的实例,而不会重新创建。
2. 不存在缓存时,创建 Bean:
• 如果没有缓存,Spring 会根据 Bean 的定义(通常是在配置文件中或通过注解)来创建一个新的 Bean 实例。
• 这会触发依赖注入、初始化等步骤,具体过程取决于 Bean 的定义和作用域。
3. 作用域的管理:
• 如果 Bean 定义为单例(默认作用域),它将保存在容器中,之后的每次调用 getBean 都会返回同一个实例。
• 如果 Bean 定义为原型(prototype)作用域,每次调用 getBean 都会创建一个新的实例。
4. 支持多种类型的返回:
• getBean 方法支持通过类型、名称或者同时结合这两者来查找 Bean。可以根据不同的参数传递方式,Spring 会返回对应类型的 Bean。
• 如果 Bean 的定义中有多个候选项,Spring 会根据匹配策略(例如按名称、按类型等)来决定返回哪个 Bean,若无法找到匹配的 Bean,则抛出异常。
5. 依赖注入与后处理:
• 获取到 Bean 实例后,Spring 会处理依赖注入,注入该 Bean 的依赖对象(如果存在的话)。
• 此外,Spring 会对 Bean 进行后处理,例如 AOP 代理、初始化方法的调用等。
6. 异常处理:
• 如果指定的 Bean 不存在,Spring 会抛出 NoSuchBeanDefinitionException 异常。
• 如果多个符合条件的 Bean 存在,Spring 会抛出 NoUniqueBeanDefinitionException 异常。

核心代码分析

Spring 中 getBean 的具体实现主要在 AbstractBeanFactory 或 DefaultListableBeanFactory 类中。以下是 getBean 方法的一个简化版本:

public Object getBean(String name) throws BeansException {
// 1. 检查是否缓存中存在实例
Object bean = getSingleton(name);

// 2. 如果缓存中没有,创建新的 Bean 实例
if (bean == null) {
    bean = createBean(name);
}

// 3. 返回实例
return bean;

}

详细步骤
1. getSingleton:
• 这是一个检查缓存的过程。Spring 会维护一个缓存(通常是 singletonObjects)来存储已创建的单例 Bean。如果某个 Bean 的名称对应的实例存在于缓存中,getSingleton 会直接返回该实例。
2. createBean:
• 如果缓存中没有该 Bean,createBean 会负责创建一个新的 Bean 实例。这个过程包括:
• 创建一个新的 Bean 实例(通过反射或构造函数注入)。
• 填充该 Bean 的属性(依赖注入)。
• 调用 Bean 的初始化方法(如果有的话)。
• 注册 Bean 后处理器(例如 AOP)。
3. 作用域处理:
• 对于原型 Bean,Spring 会创建一个新的实例并返回,不会缓存。
• 对于单例 Bean,Spring 会将创建的实例缓存起来,后续请求都会返回缓存中的实例。
4. 异常抛出:
• 如果 getBean 找不到指定的 Bean,它会抛出 NoSuchBeanDefinitionException。
• 如果请求多个符合条件的 Bean,Spring 会抛出 NoUniqueBeanDefinitionException。

总结

Spring 的 getBean 方法的主体思路是先从缓存中查找 Bean 实例,如果不存在则创建并返回该实例。在此过程中,会考虑 Bean 的作用域、依赖注入、初始化等步骤。getBean 是 Spring 容器的核心方法之一,支持灵活的 Bean 查找和管理。

源码的步骤:

  1. 这里解析bean的真正name,如果bean是工厂类,name前缀会加&,需要去掉
  2. 无参单例先从缓存中尝试获取
  3. 如果bean实例还在创建中,则直接抛出异常
  4. 如果bean definition 存在于父的bean工厂中,委派给父Bean工厂获取
  5. 标记这个beanName的实例正在创建确保它的依赖也被初始化
  • 真正创建
  • 单例时
    
  • 原型时
    
  • 根据bean的scope创建
    

二、Spring如何解决循环依赖问题
首先我们需要说明,Spring只是解决了单例模式下属性依赖的循环问题;Spring为了解决单例的循环依赖问题,使用了三级缓存。
image
image
具体的源码

分析getSingleton()的整个过程,Spring首先从一级缓存singletonObjects中获取。若是获取不到,而且对象正在建立中,就再从二级缓存earlySingletonObjects中获取。若是仍是获取不到且容许singletonFactories经过getObject()获取,就从三级缓存singletonFactory.getObject()(三级缓存)获取,若是获取到了则从三级缓存移动到了二级缓存。

image

但其实Spring只能解决Setter方法注入的依赖,对于构造器注入的无法完成,这是因为构造器注入的是属于强制性的,Spring 必须在创建 Bean 时完全满足依赖关系,因此如果发生循环依赖,Spring 会抛出异常。

image

三、Spring中Bean的生命周期
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
image

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions