Skip to content

Spring学习_Spring_Bean的生命周期

一、基础概念 ​

梳理一下 关于 SpringBean 生命周期的一些概念和理解。

Spring Bean 指的是Spring 容器中的对象,这里讲述 Bean 的生命周期一般指的是 单例 Bean。

Spring Bean 的四个阶段 ​

如果只是讲述四个笼统的阶段,那么Spring Bean 的生命周期可以分为:实例化 Instantiation → 属性赋值 Populate → 初始化 Initialization → 销毁 Destruction。

一般而言,Spring Bean 在初始化完成之后,就代表这个Bean 在容器中是可用的。

在面试题中,有可能有问一下普通的 Java 对象 和 Spring Bean 对象的生命周期的区别。

可以看一下下面这个回答:

普通Java对象的生命周期是由Java语言规则控制的,从对象的创建(实例化)开始,到被垃圾回收器回收结束。对象的创建和销毁非常直接,与对象引用的存在时间直接相关。

Spring Bean的生命周期更为复杂,因为Spring框架控制着Bean的整个生命周期。这包括了Bean的创建、初始化后的处理、以及销毁前的处理。Spring通过依赖注入管理Bean的属性,还可以通过实现特定的接口或配置声明周期回调方法来在Bean的生命周期的不同阶段执行特定的操作。这为在Bean创建和销毁过程中加入自定义逻辑提供了机会。

// 普通Java对象生命周期:
// 1. 声明: MyClass obj;
// 2. 实例化: obj = new MyClass();
// 3. 使用: obj.method();
// 4. 垃圾回收: 不再有引用指向obj时,由垃圾回收器回收

// Spring Bean生命周期:
// 1. 实例化Bean
// 2. 设置Bean属性
// 3. 如果Bean实现了BeanNameAware接口, 调用setBeanName方法
// 4. 如果Bean实现了BeanFactoryAware接口, 调用setBeanFactory方法
// 5. 如果Bean实现了ApplicationContextAware接口, 调用setApplicationContext方法
// 6. 如果存在与Bean相关的BeanPostProcessors, 调用postProcessBeforeInitialization方法
// 7. 如果Bean实现了InitializingBean接口, 调用afterPropertiesSet方法
// 8. 如果Bean配置了init-method, 调用指定的初始化方法
// 9. 如果存在与Bean相关的BeanPostProcessors, 调用postProcessAfterInitialization方法
// 10. Bean现在可以使用了
// 11. 如果容器关闭, 如果Bean实现了DisposableBean接口, 调用destroy方法
// 12. 如果Bean配置了destroy-method, 调用指定的销毁方法

言归正传,我们继续往下看。

Spring Bean 的生命周期的扩展点 ​

前面我们可以看到关于Spring的生命周期和Java对象区别的回答时,里面还讲述了一些关于Aware接口和 BeanPostProcessors 等内容,这些具体的点实际就是与 生命周期的扩展点相关(不同阶段中间进行的活动)。

下面我们来讲述一下具体的扩展点使用。

Bean 自身的方法 ​

在Bean的生命周期中,Bean自身是有一些特定方法是能够被调用的,以便完成其生命周期过程。

比如构造函数、getter/setter 以及 init-method 和 destory-method 所指定的方法等,而这些方法又分别对应着上文说的四个阶段:实例化、属性赋值、初始化和销毁。

这些Bean自身的方法一般是我们在配置Bean的时候就已经定义好的,

容器级别方法(BeanPostProcessor接口) ​

将这个容器级别方法理解为阶段中间容器会进行的一些操作,这些方法一般是 BeanPostProcessor 的一系列接口。

在上述讲到的Bean 四个阶段,在这四个阶段的执行过程中,进行一些前置或者后置的操作。

这些操作独立于 Bean 之外,并且会注册到 Spring 容器中,在Spring 容器创建Bean的时候,会进行一些处理。

工厂后处理器方法(BeanFactoryProcessor 接口) ​

工厂后处理器方法是用于来实现某些特定功能。

BeanFactoryPostProcessor是另一种容器级别的扩展点,它允许对Bean定义(BeanDefinition)进行读取和修改,这在Bean实例化之前执行。

Bean 级生命周期方法 ​

Bean 级生命周期方法指的是针对 Bean 实例的个性化行为

Bean级生命周期方法是指直接在Bean类中实现的接口方法,这些方法针对特定Bean实例生效。包括:

  • Aware接口:如BeanNameAware、BeanFactoryAware、ApplicationContextAware等,允许Bean获取容器相关的资源和信息。
  • InitializingBean和DisposableBean接口:分别用于自定义初始化后和销毁前的逻辑

通过直接在Bean类中实现这些接口,可以使Bean在其生命周期的特定时刻获得执行自定义逻辑的能力。

二、扩展点 ​

2.1 Spring Bean 自身的方法使用 ​

在Spring框架中,Bean的生命周期管理是通过一系列约定的方法来实现的,这些方法允许Spring容器在Bean的生命周期的不同阶段进行干预。以下是这些自身方法的详细说明,对应于Bean生命周期的四个主要阶段:实例化、属性赋值、初始化和销毁。

Bean 自身方法使用

  • 实例化
    • 构造函数(Constructor):是实例化阶段最基本的方法。Spring根据Bean的定义来调用相应的构造函数创建Bean实例。这可能是无参构造函数或带有参数的构造函数,后者用于依赖注入。
  • 属性赋值
    • Getter和Setter方法:用于属性赋值阶段。Spring通过反射调用Bean的Setter方法来注入依赖。这些方法遵循JavaBean的命名约定,例如,属性name对应于getName()和setName(String name)。
  • 初始化
    • 自定义初始化方法:可以在Bean定义中通过init-method属性指定一个方法作为Bean的初始化方法。这个方法在属性赋值之后调用,用于执行任何必要的初始化逻辑。
    • @PostConstruct注解::初始化之前调用的方法
  • 销毁
    • 自定义销毁方法:与初始化方法类似,可以在Bean定义中通过destroy-method属性指定一个方法作为Bean的销毁方法。当容器关闭时,这个方法被调用,用于执行任何必要的清理工作。
    • @PreDestroy注解:Spring容器在销毁Bean之前调用这个方法。

具体使用示例

展示如何在Spring中使用Bean自身的方法:

package com.example;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class MyBean {

    private String name;

    // 构造函数
    public MyBean() {
        System.out.println("MyBean is being constructed without arguments.");
    }

    // 带参数的构造函数,用于依赖注入
    public MyBean(String name) {
        this.name = name;
        System.out.println("MyBean is being constructed with name: " + name);
    }

    // Getter和Setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("Setting the name of MyBean to: " + name);
    }

    // 自定义初始化方法
    public void myCustomInit() {
        System.out.println("Custom init method of MyBean is called.");
    }

    // 使用@PostConstruct注解的初始化方法
    @PostConstruct
    public void postConstructInit() {
        System.out.println("@PostConstruct init method is called.");
    }

    // 自定义销毁方法
    public void myCustomDestroy() {
        System.out.println("Custom destroy method of MyBean is called.");
    }

    // 使用@PreDestroy注解的销毁方法
    @PreDestroy
    public void preDestroyCleanup() {
        System.out.println("@PreDestroy cleanup method is called.");
    }
}

接下来,在Spring配置文件或Java配置中,您需要注册这个Bean,并指定init-method和destroy-method:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="myBean" class="com.example.MyBean" init-method="myCustomInit" destroy-method="myCustomDestroy">
        <!-- 如果使用构造函数注入,可以如下配置 -->
        <constructor-arg value="John Doe"/>
    </bean>

</beans>

或者使用Java配置:

package com.example.config;

import com.example.MyBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    @Bean(initMethod = "myCustomInit", destroyMethod = "myCustomDestroy")
    public MyBean myBean() {
        return new MyBean("John Doe");
    }
}

在该示例中,MyBean类展示了如何定义构造函数、getter和setter方法、自定义的初始化和销毁方法,以及如何使用@PostConstruct和@PreDestroy注解来自动执行初始化前和销毁前的逻辑。

通过在Spring配置中指定init-method和destroy-method属性,我们可以控制Spring何时调用这些方法,从而实现对Bean生命周期的精细管理。

2.2 容器级别方法 ​

将这个容器级别方法理解为阶段中间容器会进行的一些操作,这些方法一般是 BeanPostProcessor 的一系列接口。

在上述讲到的Bean 四个阶段,在这四个阶段的执行过程中,进行一些前置或者后置的操作。

这些操作独立于 Bean 之外,并且会注册到 Spring 容器中,在Spring 容器创建Bean的时候,会进行一些处理。

BeanPostProcessor接口提供了容器级别的扩展点,允许在Bean的实例化和初始化前后插入自定义操作。这些操作包括:

  • 实例化前后
    • postProcessBeforeInstantiation
    • postProcessAfterInstantiation
  • 初始化前后
    • postProcessBeforeInitialization:在任何Bean初始化回调(如@PostConstruct注解的方法、afterPropertiesSet、自定义的init-method)之前调用。
    • postProcessAfterInitialization:在所有Bean初始化回调之后调用。

通过实现BeanPostProcessor接口并注册为Spring容器的Bean,可以对所有Bean的实例化和初始化过程进行干预。

可以理解 InstantiationAwareBeanPostProcessor 接口方法是 作为 实例化阶段的"产前产后护理";BeanPostProcessor 是 初始化阶段的 “关键调整和增强”。

具体的一个关系看下图:

image.png

补充一点关于InstantiationAwareBeanPostProcessor的描述以确保概念的完整性和准确性。

BeanPostProcessor接口和InstantiationAwareBeanPostProcessor接口的使用:

  • BeanPostProcessor:允许在Bean的初始化前后执行自定义逻辑。这包括:
    • postProcessBeforeInitialization: 在Bean初始化之前调用(如调用@PostConstruct注解的方法、InitializingBean的afterPropertiesSet方法或自定义的init-method之前)。
    • postProcessAfterInitialization: 在Bean初始化之后调用(如上述初始化方法执行之后)。
  • InstantiationAwareBeanPostProcessor:是BeanPostProcessor的一个扩展,提供了更多控制,包括:
    • postProcessBeforeInstantiation: 在Bean实例化之前调用,允许返回一个代理对象来代替真正的实例。
    • postProcessAfterInstantiation: 在Bean实例化之后、设置属性之前调用,允许对Bean实例进行额外的处理。

通过这些接口,Spring允许开发者在Bean生命周期的关键阶段介入,提供了极高的灵活性来定制Bean的行为,比如通过代理模式增强Bean、修改Bean属性、注入额外的依赖等。

这些特性使得Spring非常适合于企业级应用的开发,因为它们允许面向切面的编程(AOP)、事务管理等高级功能的实现。

示例:

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之前执行的逻辑
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之后执行的逻辑
        return bean;
    }
}

通过注册上述BeanPostProcessor的实现类到Spring容器,可以实现对所有Bean实例化和初始化过程的自定义干预。

这不仅提高了代码的可维护性和可扩展性,也为实现复杂的业务逻辑提供了便利。

2.3 工厂后处理器方法 ​

BeanFactoryProcessor 一系列接口

包括 AspectJWeavingEnabler、CustomAutowireConfigurer、ConfigurationClassPostProcessor 等。

这些都是 Spring 框架中已经实现好的 BeanFactoryPostProcessor,用来实现某些特定的功能

BeanFactoryProcessor 接口 vs BeanPostProcessor接口

BeanFactoryPostProcessor 接口和 BeanPostProcessor 接口都是 Spring 框架中用于定制和扩展 Bean 的关键接口,但它们的作用和时机略有不同。

BeanFactoryPostProcessor 接口:

  1. 作用: BeanFactoryPostProcessor 接口用于在 Spring 容器实例化 Bean 之前修改或定制 BeanFactory 的配置。

  2. 时机: 在 Spring 容器读取了 Bean 的定义(配置元数据)但在实例化任何 Bean 之前,BeanFactoryPostProcessor 接口提供了机会来修改 Bean 的定义,例如修改属性值、添加属性等。

  3. 实现方法: 实现 postProcessBeanFactory 方法,该方法传递了 BeanFactory 对象,可以在此方法中修改 BeanFactory 的配置。

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;

public class MyBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 在这里可以修改 BeanFactory 的配置
    }

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        // 在这里可以注册新的 BeanDefinition
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyBean.class);
        registry.registerBeanDefinition("myBean", builder.getBeanDefinition());
    }
}

BeanPostProcessor 接口

  1. 作用: BeanPostProcessor 接口用于在 Spring 容器实例化 Bean 后,在 Bean 的初始化前后执行一些自定义的逻辑。

  2. 时机: 当 Bean 被实例化后,但在调用其初始化方法(如果有的话)之前,BeanPostProcessor 提供了 postProcessBeforeInitialization 和 postProcessAfterInitialization 方法用于在初始化阶段进行定制操作。

  3. 实现方法: 实现 BeanPostProcessor 接口的两个方法,可以在这两个方法中添加定制逻辑。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之前的逻辑
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 在初始化之后的逻辑
        return bean;
    }
}

总结

  • BeanFactoryPostProcessor 主要用于修改整个 BeanFactory 的配置,它在 Bean 实例化之前执行。
  • BeanPostProcessor 主要用于在每个 Bean 的初始化阶段添加自定义逻辑,它在 Bean 实例化后,初始化方法调用前后执行。

在实际应用中,可以同时使用这两个接口来完成更复杂的定制需求。

2.4 Bean 级生命周期方法 ​

关于 Bean 级生命周期方法的理解:

  • 这些方法提供了针对 Bean 实例的个性化行为,允许 Bean 在其生命周期的关键点做出响应。

通过这些方法,是可以对于某个Bean实例进行个性化操作的。

可以理解为 Bean 类直接实现接口的方法,比如 BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean、DisposableBean 等方法,这些方法只对当前 Bean 生效。

Aware 类型的接口

Aware 类型的接口的作用就是让我们能够拿到 Spring 容器中的一些资源。

基本都能够见名知意,Aware 之前的名字就是可以拿到什么资源,例如 BeanNameAware 可以拿到 BeanName,以此类推。

三、Spring Bean 详细生命周期 ​

Spring 的生命周期基本上是很多面试的时候会遇到的一个问题,其中深度一些可能会问一下相关的源码实现;

这部分内容主要还是围绕IOC和AOP的一个实现源码的学习,以及如何实现的;如果有相关学习,并对此有所思考,可能是成为面试官比较亲耐的一个考查因素。

Bean 的生命周期

  • Bean 容器找到配置文件中 Spring Bean 的定义。
  • Bean 容器利用 Java Reflection API 创建一个 Bean 的实例。
  • 如果涉及到一些属性值 利用 set() 方法设置一些属性值。
  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName() 方法,传入 Bean 的名字。
  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader() 方法,传入 ClassLoader 对象的实例。
  • 如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanFactory() 方法,传入 BeanFactory 对象的实例。
  • 与上面的类似,如果实现了其他 * .Aware 接口,就调用相应的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行 postProcessBeforeInitialization() 方法
  • 如果 Bean 实现了 InitializingBean 接口,执行 afterPropertiesSet() 方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行 postProcessAfterInitialization() 方法
  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

Spring Bean生命周期详细回顾:

  1. 实例化Bean:Spring容器先通过构造器(或者对于FactoryBean来说是通过FactoryBean的getObject()方法)来创建Bean实例。
  2. 填充属性:Spring容器把值和Bean的引用注入到Bean对应的属性中。
  3. 调用BeanNameAware的setBeanName()方法:如果Bean实现了BeanNameAware接口,Spring将Bean的ID传递给setBeanName()方法。
  4. 调用BeanFactoryAware的setBeanFactory()方法:如果Bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。
  5. 预初始化(@PostConstruct注解方法):通过Bean的postProcessBeforeInitialization()方法。
  6. 初始化:如果Bean实现了InitializingBean接口,Spring将调用其afterPropertiesSet()方法。此外,如果Bean在配置文件中定义了init-method属性,该方法也会被调用。
  7. 后初始化(BeanPostProcessor):通过Bean的postProcessAfterInitialization()方法,可以对Bean进行额外的处理。
  8. Bean准备就绪:此时,Bean已经准备好被应用中使用了,处于完全初始化状态。
  9. 销毁前(@PreDestroy注解方法):当容器关闭时,如果Bean实现了DisposableBean接口,Spring将调用其destroy()方法。同样,如果Bean使用了destroy-method声明了销毁方法,该方法也会被调用。

通过这个详细的生命周期,我们可以看到Spring在Bean的创建和销毁过程中提供了丰富的扩展点,使得我们可以根据需要插入自己的代码,进行自定义的处理。

四、源码解析 ​

在我们讲到 IOC 的时候,它在Spring 框架的实际实现主要是依赖于BeanFactory接口及其子接口ApplicationContext。

IOC 的实现是比较复杂的一个过程,涉及到了很多组件和概念。

在前面的基础概念中,出现过 BeanDefinition、 BeanFactoryPostProcessor、 BeanPostProcessor 等词,这里对相关概念做一个小的总结。

to be contined...

这部分内容需要整合,是写的有点问题的,逻辑关联不强,重复性太高。

基础概念 ​

  1. BeanFactory接口
  • 功能:BeanFactory是Spring IoC容器的核心接口,它定义了IoC容器的基本功能,如获取bean、检查bean的存在等。
  • 实现类:XmlBeanFactory(已弃用)、DefaultListableBeanFactory等。
  1. ApplicationContext接口
  • 功能:ApplicationContext是BeanFactory的子接口,提供了更完整的功能,比如国际化支持、事件传播等。它是Spring中最常用的IoC容器接口。
  • 实现类:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、AnnotationConfigApplicationContext等。
  1. BeanDefinition及其解析
  • 功能:BeanDefinition表示Spring IoC容器中管理的bean的定义信息,包括类名、作用域、生命周期回调等。
  • 实现:Spring通过读取配置文件(XML、Java Config)解析bean定义,并将解析结果封装为BeanDefinition对象。
  1. BeanFactoryPostProcessor接口
  • 功能:允许在容器实例化任何bean之前读取并修改bean的定义(即BeanDefinition)。可以用于自定义修改bean定义的逻辑。
  • 实现类:PropertyPlaceholderConfigurer、CustomEditorConfigurer等。
  1. BeanPostProcessor接口
  • 功能:提供了修改新实例化的bean对象的扩展点,比如AOP代理的创建就是在这一步骤中实现的。
  • 实现类:AutowiredAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor等。
  1. 依赖注入
  • 功能:在bean的实例化过程中,Spring IoC容器会根据BeanDefinition中的信息,通过反射等技术,自动将声明的依赖注入到bean中。
  • 实现:主要通过BeanWrapper实现属性的设置,AutowiredAnnotationBeanPostProcessor处理@Autowired注解等。

阅读链路

  1. 启动入口:从ApplicationContext的实现类开始,了解容器的初始化过程。
  2. Bean定义的解析与注册:深入到如何解析配置(XML、注解)并将解析结果转换为BeanDefinition,以及BeanDefinition是如何注册到容器中的。
  3. Bean的创建与依赖注入:探究容器是如何创建bean实例、完成依赖注入的。
  4. 生命周期管理:了解BeanPostProcessor和BeanFactoryPostProcessor在bean生命周期中的作用。
  5. 高级特性:AOP、事件监听等高级特性是如何与IoC容器整合的。

相关概念回顾 ​

Spring上下文

从代码级别来说,就是指Spring Context

从源码级别,我们初始化Spring Context的时候,一堆的Spring组件围绕在一起,使其能够正常工作,这个状态就被称为Spring环境。

Spring 初始化操作

具体操作可以见下#ClassPathXmlApplicationContext 的构造方法哪里会被加载并使用

使用前需要引入 spring-context 相关的依赖,初始化Bean可以通过注解的方式也可以通过xml的方式。

BeanFactory 与 ApplicationContext

先了解一下 BeanFactory 与 ApplicationContext 接口两个的作用与概念:

  • org.springframework.beans 和 org.springframework.context 包是Spring Framework的IoC容器的基础。
  • BeanFactory 提供了配置框架和基本功能,提供了一种高级配置机制,能够管理任何类型的对象。
  • ApplicationContext 是 BeanFactory 的一个子接口,相比于 BeanFactory 来说,增加了更多的企业特定功能, 是 BeanFactory 的一个完整的超集。
  • BeanFactory 实现了延迟加载(懒加载),只有在请求获取Bean时(例如,通过getBean()方法),容器才会创建该Bean。这意味着如果应用中未使用某个Bean,它就不会被实例化。
  • ApplicationContext其下管理的 Bean 是在IOC容器初始化的时候完成 Bean 实例化。

实例化 Instantiation

其中第一阶段 —— 实例化 Instantiation,

Bean 实例化的时机分为两种,一种是 BeanFactory,还有一种是 ApplicationContext;

下面是两者差别:

  • BeanFactory
    • 其下管理的Bean 在使用到Bean的时候 才会进行实例化Bean操作(懒加载策略)
  • ApplicationContext
    • 其下管理的 Bean 在IOC容器初始化的时候完成 Bean 实例化。
    • ApplicationContext是BeanFactory的子接口,复杂程度更高一些。
    • 如AnnotationConfigApplicationContext和ClassPathXmlApplicationContext等,提供了多种方便的方式来创建ApplicationContext实例

ApplicationContext

org.springframework.context.ApplicationContext 接口代表Spring IoC容器,负责实例化、配置和组装bean。

AbstractApplicationContext

AbstractApplicationContext 实现了 ApplicationContext 接口,提供了这个接口的大部分通用功能。

它是实际应用上下文类(如 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext)的父类

通过继承和扩展 AbstractApplicationContext,Spring 允许开发者自定义应用上下文的行为,以满足特定的业务需求。

ClassPathXmlApplicationContext

ClassPathXmlApplicationContext 的构造方法哪里会被加载并使用?

以下是几个典型场景,其中可能会加载并使用 ClassPathXmlApplicationContext 的构造方法:

  1. Java 应用的主方法 (main)

在一个标准的 Java 应用程序中,你可以在 main 方法中创建 ClassPathXmlApplicationContext 的实例来启动 Spring 容器。这是最常见的用法。

public class MyApp {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 使用 context 获取 Bean 实例...
    }
}

在这个例子中,ClassPathXmlApplicationContext 用于加载名为 "applicationContext.xml" 的配置文件。

  1. Web 应用程序

在基于 Servlet 的传统 Web 应用程序中,可以在 Servlet 的 init 方法中创建 ClassPathXmlApplicationContext,或者使用 Spring 的 ContextLoaderListener 在 Web 应用启动时自动加载 Spring 上下文。

  1. 单元测试

在编写 Spring 应用的单元测试时,可以在测试类中创建 ClassPathXmlApplicationContext 来加载所需的 Spring 配置,并进行测试。

public class MyTest {
    @Test
    public void testSomeService() {
        ApplicationContext context = new ClassPathXmlApplicationContext("testContext.xml");
        MyService myService = context.getBean(MyService.class);
        // 执行测试...
    }
}

在这里,测试使用了单独的配置文件 "testContext.xml"。

  1. Spring Boot 应用

使用 Spring Boot 时通常不直接使用 ClassPathXmlApplicationContext

Spring Boot 提供了基于注解的配置和自动配置的能力,一般是使用注解配置的方式进行声明Bean操作 ,但在一些旧的或特殊的情况下,可能仍然需要手动加载 XML 配置的方式。

容器级别方法 ​

这部分内容待后续完善分析。

源码内容分析(容器级别方法)

需要去了解Bean的生命周期,这个源码对应的方法是必须去了解和看的。

InstantiationAwareBeanPostProcessor 接口分析

查看源码,可以看到 InstantiationAwareBeanPostProcessor 接口是继承 BeanPostProcessor

public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor

BeanPostProcessor

public interface BeanPostProcessor {  
    @Nullable  
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {  
        return bean;  
    }  
  
    @Nullable  
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {  
        return bean;  
    }  
}

AbstractAutowireCapableBeanFactory#createBean

// 创建Bean实例的方法,接收Bean的名称、RootBeanDefinition(Bean的定义信息)和参数数组
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    // 如果启用了跟踪日志,输出创建Bean实例的跟踪信息
    if (this.logger.isTraceEnabled()) {
        this.logger.trace("Creating instance of bean '" + beanName + "'");
    }

    // 解析Bean的类信息,如果已经有解析过的类信息,使用之前解析得到的类信息
    RootBeanDefinition mbdToUse = mbd;
    Class<?> resolvedClass = this.resolveBeanClass(mbd, beanName, new Class[0]);
    // 如果解析得到的类信息不为空,且当前Bean的定义信息没有指定类信息,则更新Bean的定义信息
    if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
        mbdToUse = new RootBeanDefinition(mbd);
        mbdToUse.setBeanClass(resolvedClass);
    }

    try {
        // 准备处理方法的覆盖,即准备解析方法注解
        mbdToUse.prepareMethodOverrides();
    } catch (BeanDefinitionValidationException var9) {
        // 如果方法注解解析失败,抛出BeanDefinitionStoreException异常
        throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed", var9);
    }

    Object beanInstance;
    try {
        // 在实例化Bean之前,尝试调用BeanPostProcessor的beforeInstantiation方法
        beanInstance = this.resolveBeforeInstantiation(beanName, mbdToUse);
        // 如果beforeInstantiation方法返回非空,表示已经创建了Bean实例,直接返回该实例
        if (beanInstance != null) {
            return beanInstance;
        }
    } catch (Throwable var10) {
        // 如果beforeInstantiation方法抛出异常,抛出BeanCreationException异常
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed", var10);
    }

    try {
        // 执行真正的Bean创建逻辑,包括实例化、属性注入等过程
        beanInstance = this.doCreateBean(beanName, mbdToUse, args);
        // 如果启用了跟踪日志,输出Bean实例创建完成的跟踪信息
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("Finished creating instance of bean '" + beanName + "'");
        }
        // 返回创建的Bean实例
        return beanInstance;
    } catch (ImplicitlyAppearedSingletonException | BeanCreationException var7) {
        // 如果Bean创建过程中出现了异常,抛出异常
        throw var7;
    } catch (Throwable var8) {
        // 如果Bean创建过程中出现了未捕获的异常,抛出BeanCreationException异常
        throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", var8);
    }
}

Bean 创建流程入口 refresh() ​

Bean 创建流程入口 ​

这里直接跟一下源码看一下相关内容

下面的代码是从 spring-context-5.2.4.RELEASE 版本中的 AbstractApplicationContext 抽象类下相关方法和内容说明。

在实际应用上下文类中(如 ClassPathXmlApplicationContext 和 AnnotationConfigApplicationContext),他们的构造方法中会调用这个 refresh() 方法类进行初始化 Spring 容器。

因此可以判断出 Bean 创建流程入口 是定义在 AbstractApplicationContext 抽象类下 refresh() 方法。

refressh方法 ​

这里实际看一下相关代码 AbstractApplicationContext#refresh()

public void refresh() throws BeansException, IllegalStateException {
    // 同步锁确保容器刷新时的线程安全
    synchronized (this.startupShutdownMonitor) {

        // 准备刷新,设置启动日期和活跃状态等
        this.prepareRefresh();

        // 获取新的 BeanFactory,初始化 BeanFactory,并加载 Bean 定义
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

        // 配置 BeanFactory,设置类加载器、事件处理器等
        this.prepareBeanFactory(beanFactory);

        try {
            // 允许在 BeanFactory 标准初始化之后进行定制修改
            this.postProcessBeanFactory(beanFactory);

            // 调用在容器中注册的 BeanFactoryPostProcessor
            this.invokeBeanFactoryPostProcessors(beanFactory);

            // 注册 BeanPostProcessor,这些处理器影响所有 Bean 的创建
            this.registerBeanPostProcessors(beanFactory);

            // 初始化 MessageSource 组件,用于国际化处理
            this.initMessageSource();

            // 初始化 ApplicationEventMulticaster,用于事件广播
            this.initApplicationEventMulticaster();

            // 特定于 ApplicationContext 的刷新操作
            this.onRefresh();

            // 注册监听器到事件广播器
            this.registerListeners();

            // 初始化所有剩余的非懒加载单例
            this.finishBeanFactoryInitialization(beanFactory);

            // 完成刷新过程,通知生命周期处理器以及发布相应的事件
            this.finishRefresh();
        } catch (BeansException var9) {
            // 在上下文初始化过程中捕获并处理异常
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            // 销毁已创建的 Bean,以防有些 Bean 已经初始化了,但后续的初始化过程失败了
            this.destroyBeans();

            // 取消刷新操作,重置上下文的同步标志
            this.cancelRefresh(var9);

            // 重新抛出异常,通知外部调用者
            throw var9;
        } finally {
            // 重置公共缓存(例如 Reflection 缓存)
            this.resetCommonCaches();
        }
    }
}

可以看到初始化单例这步操作是在 this.finishBeanFactoryInitialization(beanFactory); 这里进行的

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // 如果 BeanFactory 包含名为 "conversionService" 的 Bean,并且这个 Bean 适配于 ConversionService 类型
    if (beanFactory.containsBean("conversionService") && beanFactory.isTypeMatch("conversionService", ConversionService.class)) {
        // 将这个 Bean 设置为容器的 ConversionService
        beanFactory.setConversionService((ConversionService)beanFactory.getBean("conversionService", ConversionService.class));
    }

    // 如果 BeanFactory 还没有嵌入的值解析器
    if (!beanFactory.hasEmbeddedValueResolver()) {
        // 添加一个嵌入的值解析器,用于解析占位符
        beanFactory.addEmbeddedValueResolver(strVal -> {
            return this.getEnvironment().resolvePlaceholders(strVal);
        });
    }

    // 获取所有实现 LoadTimeWeaverAware 接口的 Bean 的名称
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    
    // 遍历这些 Bean 名称
    for (String weaverAwareName : weaverAwareNames) {
        // 初始化相应的 Bean,以确保它们能够执行加载时织入(Load Time Weaving)的相关逻辑
        this.getBean(weaverAwareName);
    }

    // 将 BeanFactory 的临时类加载器设置为 null
    beanFactory.setTempClassLoader(null);

    // 冻结所有的 Bean 定义,表示注册的 Bean 定义将不再被修改或任何进一步的处理
    beanFactory.freezeConfiguration();

    // 预实例化单例,确保所有非懒加载的单例都被实例化
    beanFactory.preInstantiateSingletons();
}

五、视频学习 ​

Spring Bean 的生命周期001 ​

视频地址: https://www.bilibili.com/video/BV1584y1r7n6/

作为部分内容学习和回顾。

image.png

生产 → 使用 → 销毁

生产 ​

启动,准备容器/环境等

① 加载 Bean 定义(BeanDefinitions)

加载Bean定义

run()
→
refreshContext()
→ 
refresh()
→ 
obtainFreshBeanFactory()
→
refreshBeanFactory()
→
loadBeanDefinitions()

通过 loadBeanDefinitions 扫描所有xml配置、注解将Bean记录在 Bean定义集合 beanDefinitionMap 中

②创建 Bean 对象(createBean)

遍历“Bean定义”集合

通过 createBean 遍历 beanDefinitionMap 创建bean

创建Bean

run()
→
refreshContext()
→ 
refresh()
→ 
finishBeanFactoryInitialization()
→
preInstantiateSingletioins()
→
doGetBean()
→
createBean()

2.1.构造对象

通过 createBeanInstance 方法进行对象的构造

使用反射机制从“Bean定义”中的BeanClass拿到类的构造方法

准备参数:在单例池中,根据参数的Class类进行查找

构造对象:通过反射进行Bean的构造(如果是无参则无需准备参数直接构造)


查找Class类 当匹配到多个实例, 会再根据参数名进行匹配

2.2.填充属性

通过 populateBean 方法对 Bean 内部所需属性进行属性填充, 通常是 @Autowired 注解的变量

三级缓存进行依赖注入

2.3.初始化实例

通过 initializeBean 方法对实例进行初始化

初始化操作:

  1. 初始化容器相关信息 通过 invokeAwareMethods 方法为实现各种 Aware 接口的Bean设置诸如 beanName, beanFactory 等容器信息 Aware 接口指代:信息感知接口
  2. 通过 invokeInitMethods 方法执行 Bean 的初始化方法

该 invokeInitMethods 方法是通过实现 InitializingBean 接口而实现的 afterPropertiesSet 方法 【Bean填充属性后执行】 ((InitializingBean)bean).afterPropertiesSet()

afterPropertiesSet 

↓ 

init-Methods

↓

BeanPostProcessors

销毁操作 ​
  • 销毁操作
    • 销毁前
      • 销毁之前会执行 postProcessBeforeDestruction "销毁前处理器“,这步会执行 Bean 中 @PreDestroy 注解的方法
    • 容器销毁
      • 后续通过 destoryBeans 方法逐一“销毁”容器中的Bean,销毁的时候会执行 destroy 方法(通过registerDisposableBean方法注册的Bean,该接口只有一个方法 destroy。
      • 在Bean销毁的时候,Spring容器会调用这个方法。)
    • Bean自定义销毁方法
      • “客户销毁方法”invokeCustomDestroyMethod; → 执行Bean上自定义的 destoryMethod 方法

附录 ​

Spring Bean 生命周期流程图 ​

image.png


参考