Spring如何管理Bean的生命周期呢?

我们都知道,在面试的过程中,关于 Spring 的面试题,那是各种各样,很多时候就会问到关于 Spring的相关问题,比如 AOP ,IOC 等等,还有就是关于 Spring 是如何管理 Bean 的生命周期的相关问题,今天了不起就来和大家一起看看 Spring 是如何管理 Bean 的生命周期的。

源码分析

BeanFactory

其实我们对于这个 Spring 管理 Bean 的生命周期有时候并不需要我们去大篇幅的去背诵某块的内容,我们需要的就是学会看源代码,比如源代码中的注释部分,当我们看到这注释部分的时候,很大程度上能够帮助我们理解源码的含义。

BeanFactory是Spring框架中的一个接口,它是一个工厂类,用来创建和管理Spring中的Bean对象。

我们看源码中的注释

* <p>Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:

这句话直接翻译就是 Bean Factory 实现类应该尽可能的支持标准的生命周期接口。注释的下半段内容,就是描述的 Bean 生命周期的相关内容了。所以源码里面的注释需要我们及时的去看一下,虽然都是纯英文的,但是能读出个大概得内容,再去看源码的话,至少知道它是干嘛的方法。

Bean 的生命周期

我们在了解他如何管理的时候,我们得先知道这个 Bean 的生命周期都有哪几个阶段,知道了阶段,我们再来看它的实现。

我们先总结:

Bean 的生命周期可以总结为如下的几个阶段,

1. Bean的实例化阶段

2. Bean的设置属性阶段

3. Bean的 初始化阶段

4. Bean的销毁阶段

也有些人会细分实例化阶段,就是把实例化拆分成两部分,第一部分是注册阶段,第二部分是实例化阶段,其实区别不大。

Bean实例化阶段

在Spring框架中,Bean的实例化是一个核心过程,它涉及了多个步骤以确保Bean能够正确地被创建并注入到应用上下文中。

Bean定义注册:

  • 首先,你需要在Spring的配置文件(如XML配置文件或Java配置类)中定义Bean。这包括指定Bean的类名、作用域、初始化方法、销毁方法以及可能的依赖关系等。

  • Spring容器会读取这些配置,并将Bean定义信息存储在其内部的数据结构中,通常是BeanDefinition对象。

实例化前的准备:

  • 在实例化Bean之前,Spring会进行一些准备工作,如解析Bean定义中的属性、检查依赖关系等。

  • 如果Bean定义中引用了其他Bean,Spring会尝试先解析并实例化这些依赖Bean。

实例化:

  • 实例化是创建Bean对象的过程。Spring提供了多种实例化Bean的方式:

    • 构造器实例化:通过调用Bean的构造方法来创建实例。你可以在配置文件中指定要使用的构造方法,并提供相应的参数。

    • 静态工厂方法实例化:通过调用静态工厂方法来创建Bean实例。你需要在配置文件中指定工厂类的类名和工厂方法的名称。

    • 实例工厂方法实例化:首先实例化一个工厂Bean,然后调用该工厂Bean的某个非静态方法来创建目标Bean实例。

    • 默认构造器实例化:如果Bean定义中没有指定其他实例化方式,并且Bean类有一个无参构造器,那么Spring将使用默认构造器来实例化Bean。

  • 实例化完成后,你得到的是一个原始的对象,它还没有进行任何属性注入或初始化。

属性注入:

  • 在Bean实例化之后,Spring会进行属性注入(也称为依赖注入)。这包括将Bean定义中指定的属性值或对其他Bean的引用注入到Bean的相应属性中。

  • Spring支持多种属性注入方式,如基于字段的注入、基于setter方法的注入和基于构造器的注入等。

BeanPostProcessor处理:

在Bean的属性注入完成后,但Bean的初始化方法执行之前,Spring会调用已注册的BeanPostProcessor接口的postProcessBeforeInitialization方法。这是一个可选的步骤,你可以通过实现该接口并注册相应的BeanPostProcessor来在Bean初始化前后执行自定义的逻辑。

初始化:

  • 接下来,Spring会调用Bean定义中指定的初始化方法(如果有的话)。这通常是在Bean类中定义的某个方法,并用特定的注解(如@PostConstruct)或XML配置中的元素的init-method属性来指定。

  • 初始化方法是Bean在准备好接受请求之前进行必要设置或执行特定任务的地方。

BeanPostProcessor再处理:

在Bean初始化方法执行之后,Spring会再次调用已注册的BeanPostProcessor接口的postProcessAfterInitialization方法。这是另一个可选的步骤,你可以在这里执行一些清理或后处理操作。

Bean就绪:

经过上述步骤后,Bean就已经被完全创建并初始化了。现在它可以被应用上下文中的其他组件使用或注入到其他Bean中。

到这里,我们的实例化就说完了,记下来看第二阶段。

Bean的设置属性阶段

Bean的设置属性阶段(也称为属性注入或依赖注入)是Bean生命周期中的一个重要环节。这个阶段发生在Spring容器创建Bean的实例之后,但在Bean被实际使用之前。

  • 当Spring容器创建一个Bean的实例后,它会检查该Bean是否有需要注入的属性。这些属性可能是其他的Bean、基本数据类型、集合、Map等。

  • Spring会查找与这些属性对应的配置信息(可能是XML中的标签、注解中的值或其他配置方式),并将它们注入到Bean的相应字段或setter方法中。

注入方式:

  • 字段注入:通过直接在字段上使用@Autowired或其他相关注解来实现。但请注意,字段注入在某些情况下可能导致测试困难或难以遵循良好的封装原则。

  • 构造函数注入:在构造函数参数上使用@Autowired或其他相关注解。这是推荐的方式之一,因为它确保了Bean在创建时就已经拥有所有必需的依赖项,并且这些依赖项是不可变的。

  • setter方法注入:在setter方法上使用@Autowired或其他相关注解。这种方式允许Bean在创建后的某个时间点接收其依赖项。

既然我们已经把这个属性设置完毕了,那么就要开始后进行初始化阶段了。

Bean 的初始化

  • Bean Aware接口回调

  • Bean初始化前操作

  • Bean初始化操作

  • Bean初始化后操作

  • Bean初始化完成操作

BeanAware接口回调

  private void invokeAwareMethods(final String beanName, final Object bean) {
  if (bean instanceof Aware) {
   if (bean instanceof BeanNameAware) {
    ((BeanNameAware) bean).setBeanName(beanName);
   }
   if (bean instanceof BeanClassLoaderAware) {
    ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());
   }
   if (bean instanceof BeanFactoryAware) {
    ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
   }
  }
 }

Bean初始化前操作

  @Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
  throws BeansException {

 Object result = existingBean;
 for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
  result = beanProcessor.postProcessBeforeInitialization(result, beanName);
  if (result == null) {
   return result;
  }
 }
 return result;
}

Bean初始化操作

调用InitializingBean接口的afterPropertiesSet方法 调用定义bean的时候指定的初始化方法。

 public interface InitializingBean {

 /**
  * Invoked by the containing {@code BeanFactory} after it has set all bean properties
  * and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
  * <p>This method allows the bean instance to perform validation of its overall
  * configuration and final initialization when all bean properties have been set.
  * @throws Exception in the event of misconfiguration (such as failure to set an
  * essential property) or if initialization fails for any other reason
  */
 void afterPropertiesSet() throws Exception;

} 

Bean初始化后阶段

 public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
   throws BeansException {

  Object result = existingBean;
  for (BeanPostProcessor processor : getBeanPostProcessors()) {
   Object current = processor.postProcessAfterInitialization(result, beanName);
   if (current == null) {
    return result;
   }
   result = current;
  }
  return result;
 }

Bean初始化完成操作

public interface SmartInitializingSingleton {

 /**
  * Invoked right at the end of the singleton pre-instantiation phase,
  * with a guarantee that all regular singleton beans have been created
  * already. {@link ListableBeanFactory#getBeansOfType} calls within
  * this method won't trigger accidental side effects during bootstrap.
  * <p><b>NOTE:</b> This callback won't be triggered for singleton beans
  * lazily initialized on demand after {@link BeanFactory} bootstrap,
  * and not for any other bean scope either. Carefully use it for beans
  * with the intended bootstrap semantics only.
  */
 void afterSingletonsInstantiated();

}

当我们完成了初始化之后,使用完成,最后 Bean 就要走到销毁阶段了。

Bean 的销毁

 @Override
 public void destroyBean(Object existingBean) {
  new DisposableBeanAdapter(
    existingBean, getBeanPostProcessorCache().destructionAware, getAccessControlContext()).destroy();
 }

这里需要注意的是

  • 当容器关闭时,或者当单例 Bean 的作用域结束时,Spring 会销毁 Bean 的实例。

  • 对于非单例 Bean(如 prototype 作用域的 Bean),它们会在每次请求时创建,并在不再需要时由 Java 的垃圾回收机制销毁。

相关推荐
陈平安Java and C1 小时前
MyBatisPlus
java
秋野酱2 小时前
如何在 Spring Boot 中实现自定义属性
java·数据库·spring boot
安的列斯凯奇2 小时前
SpringBoot篇 单元测试 理论篇
spring boot·后端·单元测试
Bunny02122 小时前
SpringMVC笔记
java·redis·笔记
blammmp2 小时前
Java EE 进阶:Spring MVC(1)
spring·java-ee·mvc
架构文摘JGWZ3 小时前
FastJson很快,有什么用?
后端·学习
BinaryBardC3 小时前
Swift语言的网络编程
开发语言·后端·golang
feng_blog66883 小时前
【docker-1】快速入门docker
java·docker·eureka
邓熙榆3 小时前
Haskell语言的正则表达式
开发语言·后端·golang
枫叶落雨2224 小时前
04JavaWeb——Maven-SpringBootWeb入门
java·maven