Spring Bean实例化过程

本文详细解析了Spring框架中Bean的实例化过程,包括BeanDefinition如何转换为Bean实例,以及依赖注入的实现机制。阐述了单例Bean的创建与注册位置,探讨了对象循环引用与依赖异常的处理策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇《Spring类扫描器记录》中, 记录了Spring扫描Class, 封装成一个个BeanDefinition的过程, ApplicationContext后续将根据这些Bean定义来创建Bean实例, BeanDefinition和Bean实例保存在的位置如下:
BeanDefinition保存到的实例变量(DefaultListableBeanFactory):
/** List of bean definition names, in registration order */
List<String> beanDefinitionNames

/** Map from bean name to merged RootBeanDefinition */
Map<String, RootBeanDefinition> mergedBeanDefinitions
Bean实例保存到的成员变量(DefaultListableBeanFactory):
/** 保存单例对象: bean名 --> bean实例 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
一个[BeanDefinition]到一个[Bean实例]是通过BeanFactory#getBean方法完成的:

BeanFactory#getBean方法执行过程:

Tags:(BeanFactory具体对应的子类是DefaultListableBeanFactory)

  1. 从单例缓存singletonObjects查找, 有则直接返回

没有则

  1. 创建实例
  2. 执行bean后置处理器,调用Bean初始化方法
    依赖注入是后置处理完成的,也是调用BeanFactory#getBean获取依赖对象
  3. 保存实例到singletonObjects中

参考百度脑图: [调用beanFactory.getBean获取/创建实例]节点

问题记录

1. 实例化Bean的位置

在上下文刷新时AbstractApplicationContext#refresh

// 执行完全部的BeanFactory后置处理
// ConfigurationClassPostProcessor会加载工程下的class到BeanDefinition
// 注册Bean后置处理器

// 根据BeanDefinition实例化所有单例Bean.
finishBeanFactoryInitialization(beanFactory);

2. 对象循环引用问题

getBean方法通过Bean后置处理器AutowiredAnnotationBeanPostProcessor注入依赖, 该后置处理器又将调用getBean获取依赖Bean, 例如有如下代码:

@Service
public class ServiceA {
    @Autowired
    ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    ServiceA serviceA;
}

BeanFactory会将创建中的bean名保存到singletonsCurrentlyInCreation, 创建中的bean实例保存到singletonFactories。

getBean("serviceA")的过程:
  1. 创建ServiceA实例
  2. 创建ServiceB实例
  3. 实例ServiceA注入到ServiceB (实例ServiceA仍在初始化中)
  4. ServiceB完成创建
  5. 实例ServiceB注入到ServiceA
  6. ServiceA完成创建

被依赖的Bean会先完成初始化
参考图片链接: Spring循环引用逻辑结构图

3. 单例Bean创建后注册到哪了?

DefaultSingletonBeanRegistry对象的singletonObjects字段, 这里注册的都是依赖已经注入, 且执行完Bean后置处理器的实例

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

4. 对象循环依赖异常

BeanCreationException: Circular depends-on relationship between
循环依赖会导致该异常, 如使用@DependsOn注解配置了依赖:

@Service
@DependsOn("permission")
public class Role {
    @Autowired
    private Permission permission;
}


@Service
@DependsOn("role")
public class Permission {
    @Autowired
    private Role role;
}

Permission,Role互相依赖, 谁无法被创建, BeanFactory将抛出异常
BeanCreationException:
Circular depends-on relationship between 'role' and 'permission'

### Spring Boot 中 Bean实例化过程与生命周期阶段 Spring 容器中的 Bean 生命周期可以分为多个阶段,这些阶段贯穿于 Bean 的创建、初始化以及销毁过程中。以下是关于 Spring Boot 中 Bean 实例化的详细解析: #### 1. **Bean 注册** 当 `ApplicationContext` 启动时,会读取配置文件或注解中的 Bean 定义,并将其注册到容器中。这一过程通常发生在 `refresh()` 方法调用期间[^3]。 ```java // 配置类或者 XML 文件中的 Bean 定义会被扫描并注册 @Configuration public class AppConfig { @Bean public MyService myService() { return new MyService(); } } ``` #### 2. **实例化 (Instantiation)** 在 Bean 被注册之后,Spring 开始对其进行实例化操作。这是通过反射机制完成的,具体逻辑位于 `AbstractAutowireCapableBeanFactory.doCreateBean()` 方法中。 - 如果存在工厂方法,则优先使用工厂方法进行实例化。 - 若无工厂方法,则直接通过造函数实例化对象。 #### 3. **属性注入 (Populate Properties)** 一旦 Bean 成功被实例化Spring 将根据依赖关系向该 Bean 注入相应的属性值。此步骤同样由 `doCreateBean()` 方法负责执行[^4]。 ```java @Service public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } } ``` #### 4. **应用后处理器 (Apply Post Processors)** 在此阶段,Spring 提供了两个重要的扩展点——`BeanPostProcessor` 和 `BeanFactoryPostProcessor`,它们分别用于处理单个 Bean 或者整个 Bean 工厂[^1]。 - **BeanFactoryPostProcessor**: 修改 BeanDefinition 属性,在 Bean 初始化之前生效。 - **BeanPostProcessor**: 对已创建好的 Bean 进行额外加工,比如代理生成等。 #### 5. **初始化回调 (Initialization Callbacks)** 如果某个 Bean 实现了特定接口(如 `InitializingBean`),那么其对应的 `afterPropertiesSet()` 方法会在本阶段被执行;另外也可以通过 `<bean>` 元素上的 `init-method` 属性指定自定义初始化方法[^2]。 ```java @PostConstruct public void init() { System.out.println("Bean has been initialized."); } ``` #### 6. **可用状态 (Ready to Use)** 经过上述所有准备工序后,此时 Bean 即可投入使用。它可能作为其他组件的一部分参与到业务逻辑当中去。 #### 7. **销毁前清理工作 (Destruction Cleanup)** 对于具有有限作用域(例如 prototype)或者是显式关闭的应用上下文而言,最终还需要释放资源。这一步骤可通过实现 `DisposableBean` 接口或是设置 `destroy-method` 来达成目标。 --- ### 总结 综上所述,Spring Boot 下的 Bean 生命周经历了一系列精心设计的过程,从最基础的对象建到最后的服务终止都得到了良好的支持。开发者能够利用各种钩子来自由操控这个流程以满足实际需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值