当前位置: 首页 > news >正文

Spring 中 Bean 的生命周期

一、实例化(Instantiation)

在 Spring 容器启动时,它会读取配置文件或者扫描注解来获取 Bean 的定义信息,也就是 BeanDefinition。然后,具体创建 Bean 实例的工作主要在AbstractBeanFactory类的createBean方法中。这个方法会根据 BeanDefinition 中的信息来决定创建 Bean 的方式,比如是通过构造函数还是工厂方法。

比如,如果是通过构造函数创建,代码大致是这样的(简化示意):

public Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {// 解析构造函数参数等Constructor<?> constructorToUse = null;// 找到合适的构造函数constructorToUse = autowireConstructor(beanName, mbd, constructorArgs, explicitArgs);// 使用构造函数创建Bean实例return instantiateBean(beanName, mbd, constructorToUse, argsToUse);
}

这里autowireConstructor方法会根据传入的参数等信息确定要使用的构造函数,然后instantiateBean方法使用这个构造函数来创建 Bean 实例。

二、属性赋值(Population)

Bean 实例创建好后,接下来就是给 Bean 的属性赋值。这主要在populateBean方法中完成,它是AbstractAutowireCapableBeanFactory类中的方法。

在这个方法里,首先会创建一个BeanWrapper对象来包装 Bean 实例,BeanWrapper提供了操作 Bean 属性的便捷方法。然后,它会获取 BeanDefinition 中定义的属性值,并通过BeanWrapper来设置到 Bean 实例上。以下是简化的代码示例:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 获取属性值PropertyValues pvs = mbd.getPropertyValues();if (bw != null) {// 如果有属性值,进行赋值if (!pvs.isEmpty()) {for (PropertyValue pv : pvs.getPropertyValues()) {String propertyName = pv.getName();Object value = pv.getValue();// 通过BeanWrapper设置属性值bw.setPropertyValue(propertyName, value);}}}
}

这里通过遍历PropertyValues中的每个属性值,调用bw.setPropertyValue方法来完成属性赋值。

三、Aware 接口的处理

如果 Bean 实现了一些 Aware 接口,比如BeanNameAwareBeanFactoryAware等,Spring 会在这个阶段调用相应的方法来设置相关的信息。

BeanNameAware为例,在AbstractAutowireCapableBeanFactory类的invokeAwareMethods方法中,会检查 Bean 是否实现了BeanNameAware接口,如果实现了,就调用其setBeanName方法,将 Bean 的名称设置进去。代码大致如下

private void invokeAwareMethods(String beanName, Object bean) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}// 类似地处理其他Aware接口,如BeanFactoryAware等
}

四、初始化(Initialization)

thod属性:在 Bean 的配置中指定一个初始化方法,比如在 XML 配置中可以这样写:

<bean id="myBean" class="com.example.MyBean" init-method="init"><!-- 属性配置等 -->
</bean>


AbstractAutowireCapableBeanFactory类的initializeBean方法中,会检查是否配置了init-method,如果有,就通过反射调用这个方法。示例代码如下:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {// 1. 处理Aware接口(如BeanNameAware、BeanFactoryAware等)if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());} else {invokeAwareMethods(beanName, bean); // 调用Aware接口方法}Object wrappedBean = bean;// 2. 执行BeanPostProcessor的前置处理(初始化前)if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}// 3. 核心:执行初始化方法(包括InitializingBean和init-method)try {invokeInitMethods(beanName, wrappedBean, mbd); // 关键方法} catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}// 4. 执行BeanPostProcessor的后置处理(初始化后)if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);}return wrappedBean;
}

五、使用(Usage)

经过前面的步骤,Bean 就可以在应用中被使用了。此时,它已经完成了实例化、属性赋值和初始化等过程,可以为其他组件提供服务。

六、销毁(Destruction)

当 Spring 容器关闭时,会对 Bean 进行销毁操作。同样有几种方式来定义销毁逻辑。

  1. 通过配置destroy-method属性:在 Bean 配置中指定销毁方法,比如在 XML 配置里:
<bean id="myBean" class="com.example.MyBean" destroy-method="destroy"><!-- 属性配置等 -->
</bean>

AbstractApplicationContext类的doClose方法中,会遍历所有的 Bean,对于配置了destroy-method的 Bean,通过反射调用其销毁方法。简化代码如下:

protected void doClose() {// 标记容器已关闭this.closed.set(true);if (this.active.get()) {try {// 获取所有单例Bean的名称String[] beanNames = getBeanDefinitionNames();for (String beanName : beanNames) {// 获取Bean实例Object singletonInstance = getSingleton(beanName, false);if (singletonInstance != null) {// 获取Bean的定义RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 如果配置了销毁方法,调用销毁方法if (mbd.getDestroyMethodName() != null) {invokeCustomDestroyMethod(beanName, mbd, singletonInstance);}}}} catch (Throwable ex) {// 处理异常}}
}

http://www.dtcms.com/a/311752.html

相关文章:

  • 知识蒸馏 - 基于KL散度的知识蒸馏 HelloWorld 示例
  • Linux网络编程【UDP网络通信demon】
  • 网页操作自动化解决方案:如何用Browser-Use+CPolar提升企业运营效率
  • React ahooks——副作用类hooks之useThrottleFn
  • 【智能体cooragent】新智能体创建相关代码解析
  • 双网卡UDP广播通信机制详解
  • 海洋大地测量基准与水下导航系列之九我国海洋PNT最新技术进展(下)
  • P13014 [GESP202506 五级] 最大公因数
  • 使用WSL2开发zephyr
  • 重型机械作业误伤预警响应时间缩短80%!陌讯多模态识别算法在工程现场的应用优化
  • 音频3A处理简介之AGC(自动增益控制)
  • RHCE认证题解
  • 自动驾驶中的传感器技术13——Camera(4)
  • 知识蒸馏 - 最小化KL散度与最小化交叉熵是完全等价的
  • stm32103如果不用32k晶振,那引脚是悬空还是接地
  • C++入门基础(三):const引用、指针和引用的关系、inline(修饰内联函数)替代宏、nullptr代替null
  • 使用docker运行vite项目
  • C++ vector底层实现与迭代器失效问题
  • 深入 Go 底层原理(十五):cgo 的工作机制与性能开销
  • 【深度学习】【三维重建】windows11环境配置PyTorch3d详细教程
  • Flutter开发 初识目录结构
  • 自动布局视图来实现聊天室的界面
  • 【iOS】KVO
  • 20250802让飞凌OK3576-C开发板在飞凌的Android14下【rk3576_u选项】适配NXP的WIFIBT模块88W8987A的蓝牙
  • OTC焊接机器人节能技巧
  • Java内存模型(Java Memory Model,JMM)
  • 关于鸦片战争的历史
  • Dify 上次文件大小突破15MB,解决办法?
  • Store / Slice / Reducer
  • 麦肯锡咨询公司PEI经典面试题目汇总