轩辕李的博客 轩辕李的博客
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

轩辕李

勇猛精进,星辰大海
首页
  • Java
  • Spring
  • 其他语言
  • 工具
  • HTML&CSS
  • JavaScript
  • 分布式
  • 代码质量管理
  • 基础
  • 操作系统
  • 计算机网络
  • 编程范式
  • 安全
  • 中间件
  • 心得
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Java

  • Spring

    • 基础

    • 框架

      • Spring容器初始化过程和Bean生命周期探究
        • 一、前言
        • 二、容器基础
          • 1、Bean工厂(BeanFactory)
          • 2、应用上下文(ApplicationContext)
          • 3、类信息织入(Aware)
        • 三、容器初始化
        • 四、Bean生成周期
          • 1、Bean的生命周期步骤
          • 2、Bean生命周期扩展概述
        • 五、Bean工厂后处理器(BeanFactoryPostProcessor)的扩展
          • 1、默认加载的BeanFactoryPostProcessor
          • 2、MyBatis的Bean工厂后处理器
          • 3、Bean定义注册后置处理器(BeanDefinitionRegistryPostProcessor)
          • 4、工厂Bean(FactoryBean)
          • 5、类路径Bean定义扫描器(ClassPathBeanDefinitionScanner)
          • 6、Bean定义(BeanDefinition)
        • 六、Bean后处理器(BeanPostProcessor)的扩展
          • 1、默认加载的BeanPostProcessor
          • 2、自定义BeanPostProcessor
        • 七、自定义初始化方法和销毁回调的扩展
          • 1、实现InitializingBean和DisposableBean接口
          • 2、使用@PostConstruct和@PreDestroy注解
        • 八、生命周期(Lifecycle)扩展
          • 1、Lifecycle 接口的定义
          • 1.1、方法说明
          • 2、Lifecycle 的使用场景
          • 3、实现 Lifecycle 接口的示例
          • 4、示例代码
          • 4.1、测试代码
          • 4.2、输出结果
          • 5、Lifecycle 的扩展接口
          • 5.1、`SmartLifecycle`
          • a、示例代码
          • 5.2、`Phased`
          • 6、Lifecycle 与 @PostConstruct 和 @PreDestroy 的区别
        • 九、总结
      • Spring容器:从依赖管理到注解配置全解析
      • Spring事件探秘
      • Spring AOP的应用
      • Spring 事务管理
      • Spring中的资源访问:Resource接口
      • Spring中的验证、数据绑定和类型转换
      • Spring表达式语言(SpELl)
      • Spring中的属性占位符
      • Spring数据缓冲区与编解码器详解
      • Spring对于原生镜像和AOT的支持
      • Spring中的数据访问:JDBC、R2DBC、ORM、Object-XML
      • Spring中的Web访问:Servlet API支持
      • Spring中的Web访问:WebSocket支持
      • Spring中的Web访问:响应式栈 WebFlux
      • Spring中的集成测试与单元测试
      • Spring与多种技术的集成
      • Spring框架版本新特性
    • Spring Boot

    • 集成

  • 其他语言

  • 工具

  • 后端
  • Spring
  • 框架
轩辕李
2023-05-18
目录

Spring容器初始化过程和Bean生命周期探究

# 一、前言

Spring Framework是一个广泛应用于Java开发的开源框架,它提供了丰富的功能和强大的特性,为开发者简化了应用程序的开发和管理。

其中,Spring容器是Spring框架的核心部分,负责管理和组织应用程序中的对象(Bean)以及它们之间的关系。

在使用Spring框架开发应用程序时,了解Spring容器的初始化过程和Bean的生命周期是至关重要的。

深入了解这些概念和流程,可以帮助开发者更好地理解Spring框架的工作原理,解决常见的问题,并编写更可靠、高效的代码。

本文将探究Spring容器的初始化过程和Bean的生命周期。我们将从Spring容器的启动、Bean的实例化、初始化回调、后置处理器等方面,详细讨论Spring容器在运行时是如何加载和管理Bean的。

# 二、容器基础

# 1、Bean工厂(BeanFactory)

BeanFactory是Spring框架中最核心的接口,它提供了高级IoC(Inversion of Control)功能来管理你的beans。简单来说,BeanFactory就是一个管理Bean生命周期的工厂。

以下是BeanFactory的主要功能:

  1. 创建Bean实例:BeanFactory负责创建Bean实例。它通过配置文件中定义的Bean定义信息,使用反射机制创建Bean实例。

  2. 初始化Bean:BeanFactory会调用Bean的初始化方法,完成Bean的初始化工作。初始化方法可以是Bean实现的InitializingBean接口的afterPropertiesSet()方法,也可以是配置文件中通过init-method属性指定的自定义初始化方法。

  3. 依赖注入:BeanFactory会负责依赖注入。它会读取配置文件中的依赖关系,然后将依赖的Bean注入到需要的Bean中。

  4. 管理Bean的作用域:BeanFactory会管理Bean的作用域。例如,对于singleton作用域的Bean,BeanFactory会确保在整个应用中只有一个Bean实例;对于prototype作用域的Bean,BeanFactory会每次都返回一个新的Bean实例。

  5. 销毁Bean:当容器关闭时,BeanFactory会负责销毁singleton作用域的Bean。销毁方法可以是Bean实现的DisposableBean接口的destroy()方法,也可以是配置文件中通过destroy-method属性指定的自定义销毁方法。

值得注意的是,虽然BeanFactory提供了基本的IoC功能,但在实际使用中,我们更多地使用ApplicationContext,它是BeanFactory的子接口,提供了更多高级特性,如事件发布、国际化支持等。

# 2、应用上下文(ApplicationContext)

ApplicationContext是Spring框架的核心接口之一,它扩展了BeanFactory接口,并提供了更多的功能和特性。

ApplicationContext接口实现了多个接口,使其具有更多的功能和特性。以下是这些接口的简要介绍:

  1. ListableBeanFactory:继承自BeanFactory接口,扩展了对Bean列表的访问能力。它允许通过名称、类型、注解等条件来检索应用程序上下文中的Bean列表。

  2. HierarchicalBeanFactory:继承自BeanFactory接口,表示具有层次结构的BeanFactory。它允许访问父BeanFactory,以实现在层次结构中查找Bean定义和实例。

  3. EnvironmentCapable:定义了获取应用程序环境的能力。通过ApplicationContext实现EnvironmentCapable接口,可以获取应用程序的环境配置,如配置属性、激活的配置文件等。

  4. MessageSource:定义了国际化消息的访问能力。ApplicationContext作为MessageSource的实现,可以加载和提供多语言的消息,用于国际化和本地化的支持。

  5. ApplicationEventPublisher:定义了发布应用程序事件的能力。通过ApplicationContext实现ApplicationEventPublisher接口,可以发布应用程序中的事件,并允许其他组件注册为事件监听器。

  6. ResourcePatternResolver:定义了加载资源模式的能力。ApplicationContext作为ResourcePatternResolver的实现,可以通过模式匹配加载资源文件,如类路径、文件系统路径、URL等。

通过实现这些接口,使得ApplicationContext成为一个强大而全面的应用程序上下文管理器。

# 3、类信息织入(Aware)

在Spring框架中,有很多以Aware结尾的接口,这些接口通常用于让Bean获取到Spring容器的一些资源。

当一个Bean实现了这些Aware接口之一,并且该Bean被Spring管理,那么当Spring创建这个Bean的实例时,会自动调用相应的Aware接口方法,将对应的资源注入到Bean中。

以下是一些常见的Aware接口的作用:

  1. BeanNameAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将这个Bean在容器中的名字注入到Bean中。这样,Bean就可以知道自己在容器中的名字。

  2. BeanClassLoaderAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将加载这个Bean的ClassLoader注入到Bean中。这样,Bean就可以加载其他的类。

  3. BeanFactoryAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将创建这个Bean的BeanFactory注入到Bean中。这样,Bean就可以获取到BeanFactory,从而访问和管理容器中的其他Bean。

  4. ResourceLoaderAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将一个ResourceLoader注入到Bean中。这样,Bean就可以加载各种资源,如文件、图片等。

  5. ApplicationContextAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将ApplicationContext注入到Bean中。这样,Bean就可以获取到ApplicationContext,从而访问和管理容器中的其他Bean,以及发布事件、获取消息源等。

  6. EnvironmentAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将环境相关的配置信息注入到Bean中。这样,Bean就可以获取到环境属性,如系统属性、环境变量等。

  7. MessageSourceAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将MessageSource注入到Bean中。这样,Bean就可以获取到国际化消息。

  8. ApplicationEventPublisherAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将ApplicationEventPublisher注入到Bean中。这样,Bean就可以发布应用事件。

  9. EmbeddedValueResolverAware:如果一个Bean实现了这个接口,那么在Bean初始化的时候,Spring会将一个StringValueResolver注入到Bean中。这样,Bean就可以解析字符串中的占位符。

这些Aware接口提供了一种让Bean获取到Spring容器资源的方式,使得Bean可以与Spring容器更紧密地集成在一起。

下面是一个示例代码,展示如何实现ApplicationContextAware接口:

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class MyBean implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public void doSomething() {
        // 使用获取到的ApplicationContext执行操作
        // 例如,获取其他Bean并调用它们的方法
        AnotherBean anotherBean = applicationContext.getBean(AnotherBean.class);
        anotherBean.anotherMethod();
    }
}

# 三、容器初始化

在Spring容器初始化的过程中,最重要的方法就是refresh()方法。这个方法是在AbstractApplicationContext类中定义的,它是一个模板方法,用于控制容器的初始化流程。

我们以AnnotationConfigApplicationContext类为例,看一下refresh()方法的实现。

启动容器

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {

    public static void main(String[] args) {
        // 创建AnnotationConfigApplicationContext实例
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();

        // 注册配置类
        applicationContext.register(AppConfig.class);

        // 启动应用上下文
        applicationContext.refresh();

        // 获取Bean实例
        MyBean myBean = applicationContext.getBean(MyBean.class);

        // 使用Bean实例
        myBean.doSomething();

        // 关闭应用上下文
        applicationContext.close();
    }
}

AbstractApplicationContext#refresh()方法的实现如下:

public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // 准备刷新操作,设置容器状态和标志
        prepareRefresh();

        // 获取新的Bean工厂实例,由子类实现
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // 对Bean工厂进行准备工作,设置各种后置处理器、属性编辑器等
        prepareBeanFactory(beanFactory);

        try {
            // 对Bean工厂进行后置处理,允许子类进行扩展
            postProcessBeanFactory(beanFactory);

            // 调用已注册在容器中的BeanFactoryPostProcessor的postProcessBeanFactory()方法
            invokeBeanFactoryPostProcessors(beanFactory);

            // 注册Bean后处理器,用于在Bean创建过程中进行拦截和处理
            registerBeanPostProcessors(beanFactory);

            // 初始化消息源,用于国际化
            initMessageSource();

            // 初始化事件广播器,用于应用程序事件的发布和监听
            initApplicationEventMulticaster();

            // 允许子类在特定的上下文中初始化其他特殊的Bean
            onRefresh();

            // 注册监听器,用于事件的监听
            registerListeners();

            // 实例化所有剩余的(非延迟初始化)单例Bean
            finishBeanFactoryInitialization(beanFactory);

            // 刷新完成的最后一步,发布相应的事件
            finishRefresh();
        } catch (BeansException ex) {
            // 发生异常时进行异常处理
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }

            // 销毁已创建的单例Bean,避免悬空资源
            destroyBeans();

            // 取消刷新操作,并设置容器状态
            cancelRefresh(ex);

            // 将异常传播给调用者
            throw ex;
        } finally {
            // 重置Spring核心中的公共缓存,释放资源
            resetCommonCaches();
        }
    }
}

protected void finishRefresh() {
    // 清除上下文级别的资源缓存,例如扫描过程中的ASM元数据
    clearResourceCaches();

    // 初始化生命周期处理器
    initLifecycleProcessor();

    // 首先,将刷新操作传播给生命周期处理器
    getLifecycleProcessor().onRefresh();

    // 发布最终的上下文刷新事件
    publishEvent(new ContextRefreshedEvent(this));

    // 如果激活了LiveBeansView,则参与到LiveBeansView MBean中
    LiveBeansView.registerApplicationContext(this);
}

这其中涉及到很多类:

  • ConfigurableApplicationContext(可配置的应用上下文):接口,扩展了ApplicationContext接口,定义了一些用于配置应用上下文的方法。提供了一些额外的方法,用于配置应用上下文。
  • ConfigurableListableBeanFactory(可配置的可列举的Bean工厂):接口,继承了ListableBeanFactory接口和ConfigurableBeanFactory接口,扩展了BeanFactory的功能。
  • AbstractApplicationContext(抽象应用上下文):抽象类,实现了ConfigurableApplicationContext接口,提供了ApplicationContext的基本实现,包括处理环境、资源加载、BeanFactory的初始化等。AbstractApplicationContext还定义了refresh()方法,作为容器初始化和刷新的入口点。
  • DefaultListableBeanFactory:实现了ConfigurableListableBeanFactory接口。它是一个默认的可配置的BeanFactory实现,用于管理Bean定义、创建Bean实例等。
  • BeanFactoryPostProcessor(Bean工厂后置处理器):接口,定义了在Bean工厂实例化和配置Bean之前对Bean的定义进行修改和扩展的方法。通过实现BeanFactoryPostProcessor接口,可以在应用程序启动时对Bean定义进行动态调整,例如修改属性值、添加额外的Bean定义等。它在容器启动阶段对Bean定义进行修改,从而影响Bean的创建和配置过程。
  • BeanPostProcessor(Bean后置处理器):接口,定义了在Bean实例化和初始化过程中对Bean进行处理和扩展的方法。通过实现BeanPostProcessor接口,可以在Bean的生命周期中进行自定义处理和修改,例如在Bean实例化后进行增强、代理等操作。它在容器实例化和初始化Bean时对Bean进行修改,可以用于添加额外的处理逻辑,实现AOP切面等。
  • LifecycleProcessor(Bean生命周期处理):接口,用于管理应用程序中组件的生命周期。它定义了一组方法,用于在应用程序启动和关闭过程中管理和触发组件的生命周期方法。
  • LiveBeansView(实时监视和管理Bean,JMX扩展):接口,它提供了一个可视化界面,用于查看应用程序中正在运行的Bean以及它们之间的关系。

这些类中最重要的是BeanFactoryPostProcessor和BeanPostProcessor,后面会详细讲到它们。

# 四、Bean生成周期

# 1、Bean的生命周期步骤

Spring Bean的生命周期是指从Spring容器创建Bean实例,到最后销毁Bean实例的过程。以下是Spring Bean生命周期的详细步骤:

  1. 实例化Bean:这是生命周期的开始,Spring Bean被实例化。Spring IoC容器通过构造函数或工厂方法创建Bean实例。

  2. 设置Bean属性:Spring IoC容器通过依赖注入填充Bean的属性。这是通过在Spring配置文件中定义的属性或构造函数参数来完成的。

  3. 调用BeanNameAware的setBeanName():如果Bean实现了BeanNameAware接口,Spring会传入Bean的ID。这可以让Bean知道自己在Spring容器中的名字。

  4. 调用BeanFactoryAware的setBeanFactory():如果Bean实现了BeanFactoryAware接口,Spring会传入当前的BeanFactory。这可以让Bean知道自己所在的BeanFactory。

  5. 调用ApplicationContextAware的setApplicationContext():如果Bean实现了ApplicationContextAware接口,Spring会传入当前的ApplicationContext。这可以让Bean知道自己所在的ApplicationContext。

  6. BeanPostProcessor的前置处理:Spring会调用所有注册的BeanPostProcessor的postProcessBeforeInitialization()方法。这是在Bean初始化之前提供的扩展点。

  7. 调用InitializingBean的afterPropertiesSet():如果Bean实现了InitializingBean接口,Spring会调用它的afterPropertiesSet()方法。这是Bean初始化的另一个扩展点。

  8. 调用自定义的初始化方法:如果在Bean配置文件中通过init-method属性指定了初始化方法,Spring会调用它。这是Bean初始化的另一个扩展点。

  9. BeanPostProcessor的后置处理:Spring会调用所有注册的BeanPostProcessor的postProcessAfterInitialization()方法。这是在Bean初始化之后提供的扩展点。

  10. Bean准备就绪:此时,Bean已经准备就绪,可以被应用程序使用了。

  11. 应用程序使用Bean:应用程序使用Bean,调用Bean的方法进行业务处理。

  12. 调用DisposableBean的destroy():如果Bean实现了DisposableBean接口,Spring会在容器关闭时调用它的destroy()方法。这是Bean销毁的一个扩展点。

  13. 调用自定义的销毁方法:如果在Bean配置文件中通过destroy-method属性指定了销毁方法,Spring会调用它。这是Bean销毁的另一个扩展点。

以上就是Spring Bean生命周期的详细过程。在这个过程中,Spring提供了多个扩展点,可以让我们在Bean初始化前后进行自定义操作。

# 2、Bean生命周期扩展概述

Bean生命周期扩展主要涉及到以下几个接口:

  • BeanFactoryPostProcessor:在 Spring 容器加载 Bean 的定义之后,但在 Bean 实例化之前,对 Bean 的定义进行修改或扩展。通过实现 BeanFactoryPostProcessor 接口,可以动态调整 Bean 的配置或注册新的 Bean。
  • BeanPostProcessor:在 Bean 实例化和初始化过程中对 Bean 进行处理,影响 Bean 的初始化和自定义操作。它是在 Bean 实例化和属性注入完成后,以及自定义初始化方法(如 InitializingBean 接口或 @PostConstruct 注解)调用之前和之后对 Bean 进行处理的接口。
  • Aware:前面已经介绍了,不赘述
  • Lifecycle 接口:用于管理 Bean 的生命周期,特别是启动和停止操作。它定义了 start() 和 stop() 方法,允许 Bean 在容器启动和关闭时执行特定的操作。
  • InitializingBean 接口:当 Bean 的属性设置完成后,在执行自定义初始化逻辑之前,Spring 调用 afterPropertiesSet() 方法。通过实现 InitializingBean 接口,可以在该方法中编写自定义的初始化逻辑。
  • DisposableBean 接口:当 Bean 即将销毁时,Spring 调用 destroy() 方法。通过实现 DisposableBean 接口,可以在该方法中编写自定义的销毁逻辑。
  • @PostConstruct 和 @PreDestroy注解:自定义的初始化方法和自定义的销毁方法。它们是通过CommonAnnotationBeanPostProcessor这个Bean后置处理器来实现的。

# 五、Bean工厂后处理器(BeanFactoryPostProcessor)的扩展

# 1、默认加载的BeanFactoryPostProcessor

Spring容器在启动过程中会注册一些BeanFactoryPostProcessor。默认情况下,下面列出的是一些在Spring 5中默认注册的BeanFactoryPostProcessor:

  1. PropertyPlaceholderConfigurer:这个后处理器允许你将${...}占位符替换为properties文件中的属性。它主要用于处理配置文件。

  2. PropertySourcesPlaceholderConfigurer:与PropertyPlaceholderConfigurer类似,但是它是基于Spring的Environment和PropertySource抽象的,用于处理Spring 3.1及以上版本的配置。

  3. PreferencesPlaceholderConfigurer:这个后处理器允许你将${...}占位符替换为Java Preferences API中定义的属性。

  4. ConfigurationClassPostProcessor:这个后处理器处理带有@Configuration注解的类,它会处理@Bean、@Import和@ComponentScan等注解。

# 2、MyBatis的Bean工厂后处理器

这里我们以MyBatis类库为例,来看看Bean工厂后处理器的扩展。

在 MyBatis 和 Spring 整合的过程中,可以通过自定义 BeanFactoryPostProcessor 来处理 Mapper 接口的注入。

MapperFactoryBean 是 MyBatis-Spring 提供的一个工厂类,用于产生 MyBatis 的 Mapper 接口实现类。它实现了BeanDefinitionRegistryPostProcessor接口,此接口继承了BeanFactoryPostProcessor接口。

下面是一个基础的示例:

public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean, ApplicationContextAware, BeanNameAware {

    // 省略其他配置属性...

    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
        if (this.processPropertyPlaceHolders) {
          processPropertyPlaceHolders();
        }
        
        ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
        scanner.setAddToConfig(this.addToConfig);
        scanner.setAnnotationClass(this.annotationClass);
        scanner.setMarkerInterface(this.markerInterface);
        scanner.setSqlSessionFactory(this.sqlSessionFactory);
        scanner.setSqlSessionTemplate(this.sqlSessionTemplate);
        scanner.setSqlSessionFactoryBeanName(this.sqlSessionFactoryBeanName);
        scanner.setSqlSessionTemplateBeanName(this.sqlSessionTemplateBeanName);
        scanner.setResourceLoader(this.applicationContext);
        scanner.setBeanNameGenerator(this.nameGenerator);
        scanner.setMapperFactoryBeanClass(this.mapperFactoryBeanClass);
        if (StringUtils.hasText(lazyInitialization)) {
          scanner.setLazyInitialization(Boolean.valueOf(lazyInitialization));
        }
        if (StringUtils.hasText(defaultScope)) {
          scanner.setDefaultScope(defaultScope);
        }
        scanner.registerFilters();
        scanner.scan(
            StringUtils.tokenizeToStringArray(this.basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
    }

    // 省略其他方法...

}

在上面的代码中,MapperScannerConfigurer 实现了 BeanFactoryPostProcessor 接口。在 postProcessBeanFactory 方法中,我们创建一个 MapperScanner 对象,并通过 setBasePackage 方法设置要扫描的包。然后调用 afterPropertiesSet 方法进行扫描。

当 Spring IoC 容器启动时,会执行所有 BeanFactoryPostProcessor 的 postProcessBeanFactory 方法。在这个方法中,MapperScanner 会扫描指定的包,并找到所有的 Mapper 接口。

对于每个接口,MapperScanner 会创建一个 BeanDefinition,并将 BeanDefinition 的工厂类设置为 MapperFactoryBean。这样,当 Spring IoC 容器需要创建 Mapper 接口的实现类时,就会使用 MapperFactoryBean 来创建。

通过这种方式,我们可以很方便地将 MyBatis 的 Mapper 接口注入到 Spring 的 IoC 容器中,而无需编写任何实现类。

这其中涉及到了一些类,下面将对这些类进行简单的介绍。

# 3、Bean定义注册后置处理器(BeanDefinitionRegistryPostProcessor)

BeanDefinitionRegistryPostProcessor 是 Spring 框架的一个接口,它扩展自 BeanFactoryPostProcessor。它的主要职责是在所有的 BeanDefinition 被加载之后,但是还没有被 Bean Factory 处理之前,提供一个扩展点,我们可以在这个扩展点上添加一些新的 BeanDefinition 或者对现有的 BeanDefinition 进行修改。

这个接口定义了两个方法:

  1. postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry): 此方法在所有应用程序的 BeanDefinition 被加载之后,但是还没有 Bean 被实例化之前调用。在这个阶段,我们可以向容器中添加一些新的 BeanDefinitions。
  2. postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory): 此方法在所有 BeanDefinition 处理之后,但是在 bean 实例化之前调用。它提供了对 BeanFactory 的访问权限。

注意,这个接口的实现类是被优先调用的。所有的 BeanDefinitionRegistryPostProcessor beans 都会先于 BeanFactoryPostProcessor beans 被加载和调用。这样就保证了在所有其他的 BeanFactoryPostProcessor beans 对 BeanDefinitions 进行修改之前,我们已经通过 BeanDefinitionRegistryPostProcessor 完成了 BeanDefinitions 的添加或者修改。

一个典型的 BeanDefinitionRegistryPostProcessor 的使用场景是 ConfigurationClassPostProcessor,这个类是一个内置的 BeanDefinitionRegistryPostProcessor,它的职责是读取带有 @Configuration 注解的类,然后解析类中的 @Bean、@Import 和 @ComponentScan 等注解,以便在运行时动态地注册 BeanDefinition。

# 4、工厂Bean(FactoryBean)

FactoryBean是Spring框架中的一个工厂bean,用于产生某一类型的bean。它允许你在Spring配置文件中使用复杂的初始化逻辑,这种初始化逻辑通常需要在编程中完成。

FactoryBean有三个重要的方法:

  • getObject():返回由FactoryBean创建的bean实例,如果isSingleton()返回true,那么这个实例会存入到Spring IoC容器中。
  • getObjectType():返回FactoryBean创建的对象类型。
  • isSingleton():返回由FactoryBean创建的对象是否为singleton。

在MyBatis中,MapperFactoryBean就是一个FactoryBean,它用于产生Mapper接口的实现类。

# 5、类路径Bean定义扫描器(ClassPathBeanDefinitionScanner)

ClassPathBeanDefinitionScanner是Spring中用来扫描类路径,查找满足条件的类,并将这些类自动转化为BeanDefinition的工具类。这是Spring注解驱动模型的基础,比如@Component、@Service、@Controller等。ClassPathBeanDefinitionScanner会扫描类路径,找到被这些注解标注的类,然后将它们转化为BeanDefinition。

ClassPathBeanDefinitionScanner的使用通常结合ClassPathScanningCandidateComponentProvider类,后者用于查找候选的组件(即可能会被实例化为bean的类)。我们可以通过指定不同的注解,来决定哪些类会被识别为候选组件。

在MyBatis中,ClassPathMapperScanner就是一个ClassPathBeanDefinitionScanner,它用于扫描类路径,找到所有的Mapper接口,并将它们转化为BeanDefinition。

# 6、Bean定义(BeanDefinition)

BeanDefinition 是 Spring Framework 中的一个核心概念,它是 Spring 容器中管理的 Bean 的定义。这个定义包含了 Bean 的各种元数据,例如 Bean 的类名、是否是抽象类、它的作用范围(Singleton 或 Prototype)、构造函数参数、属性值、以及其他特定于 Spring 的设置,如初始化方法、销毁方法等。

当你在 Spring 配置文件中定义一个 <bean> 元素,或者使用 @Component、@Service、@Repository 或 @Controller 注解标注一个类的时候,Spring 就会创建一个对应的 BeanDefinition 对象。

BeanDefinition 的主要方法包括:

  • getParentName 和 setParentName:用于获取和设置父 Bean 的名字。这个父 Bean 是一个模板,用于继承配置信息。
  • getBeanClassName 和 setBeanClassName:用于获取和设置 Bean 的全限定类名。
  • getScope 和 setScope:用于获取和设置 Bean 的作用范围,如 "singleton" 或 "prototype"。
  • getConstructorArgumentValues 和 getPropertyValues:用于获取 Bean 的构造函数参数值和属性值。
  • getFactoryBeanName 和 setFactoryBeanName:如果这个 Bean 是通过工厂方法创建的,这两个方法用于获取和设置工厂 Bean 的名字。
  • getFactoryMethodName 和 setFactoryMethodName:如果这个 Bean 是通过工厂方法创建的,这两个方法用于获取和设置工厂方法的名字。

通过操作 BeanDefinition,我们可以在运行时动态地改变 Spring 容器中 Bean 的配置。例如,我们可以通过实现 BeanFactoryPostProcessor 接口,然后在 postProcessBeanFactory 方法中获取 BeanDefinition 并进行修改。

# 六、Bean后处理器(BeanPostProcessor)的扩展

# 1、默认加载的BeanPostProcessor

Spring容器默认会装配一些内置的BeanPostProcessor。下面列出了一些在Spring 5中默认装配的BeanPostProcessor:

  1. AutowiredAnnotationBeanPostProcessor:处理@Autowired和@Value注解。它将负责自动装配bean属性。

  2. CommonAnnotationBeanPostProcessor:处理JSR-250规范的注解,例如@PostConstruct、@PreDestroy和@Resource。

  3. PersistenceAnnotationBeanPostProcessor:处理JPA注解,如@PersistenceContext和@PersistenceUnit。

  4. RequiredAnnotationBeanPostProcessor:处理Spring的@Required注解。

  5. ApplicationListenerDetector:检测是否bean是一个应用程序事件监听器,如果是的话,将其添加到事件多播器。

  6. EventListenerMethodProcessor:处理@EventListener注解。

  7. ScheduledAnnotationBeanPostProcessor:处理@Scheduled和@Schedules注解。

  8. AsyncAnnotationBeanPostProcessor:处理@Async注解。

  9. ConfigurationClassPostProcessor:处理@Configuration类,处理@Bean、@Import和@ComponentScan等注解。

注意,对于一些特性如AOP、数据校验、事务管理等,也会有相应的BeanPostProcessor,比如AsyncAnnotationBeanPostProcessor、PersistenceExceptionTranslationPostProcessor等,但他们的注册通常需要额外的配置或者依赖。

# 2、自定义BeanPostProcessor

在Spring中,你可以通过实现BeanPostProcessor接口来扩展bean的初始化过程。这个接口有两个方法:postProcessBeforeInitialization和postProcessAfterInitialization。

以下是一个简单的BeanPostProcessor扩展示例,它在有@Log注解的bean初始化前后都会打印一条信息:

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

public class CustomBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (AnnotationUtils.findAnnotation(bean.getClass(), Log.class) != null) {
            System.out.println("Before initialization of bean " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (AnnotationUtils.findAnnotation(bean.getClass(), Log.class) != null) {
            System.out.println("After initialization of bean " + beanName);
        }
        return bean;
    }
}

为了让Spring知道这个BeanPostProcessor,你需要在你的Spring配置中将它声明为一个bean:

<bean class="com.example.CustomBeanPostProcessor"/>

或者如果你使用Java配置,你可以将它声明为一个@Bean:

@Configuration
public class AppConfig {

    @Bean
    public CustomBeanPostProcessor customBeanPostProcessor() {
        return new CustomBeanPostProcessor();
    }
}

然后,每次当Spring初始化一个@Log注解的bean时,就会调用这个BeanPostProcessor。具体来说,postProcessBeforeInitialization方法会在BeanPostProcessor的afterPropertiesSet(对于InitializingBean)或自定义的初始化方法(如果指定了的话)之前被调用。然后,postProcessAfterInitialization方法会在afterPropertiesSet或自定义的初始化方法之后被调用。

# 七、自定义初始化方法和销毁回调的扩展

# 1、实现InitializingBean和DisposableBean接口

InitializingBean和DisposableBean接口是Spring中两个用于bean生命周期管理的接口。InitializingBean接口提供了一个afterPropertiesSet方法,这个方法会在Spring完成bean的初始化之后调用。DisposableBean接口提供了一个destroy方法,这个方法会在Spring销毁bean之前调用。

下面是一个示例,这个bean同时实现了InitializingBean和DisposableBean接口:

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class LifecycleBean implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Bean is initialized");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Bean will be destroyed");
    }
}

然后在Spring配置文件中定义这个bean:

<bean id="lifecycleBean" class="com.example.LifecycleBean"/>

或者如果你使用Java配置:

@Configuration
public class AppConfig {

    @Bean
    public LifecycleBean lifecycleBean() {
        return new LifecycleBean();
    }
}

当Spring启动并创建LifecycleBean实例时,你会看到"Bean is initialized"的输出。然后,当Spring容器关闭并销毁LifecycleBean实例时,你会看到"Bean will be destroyed"的输出。

注意,这些方法的调用时间取决于bean的作用范围。对于singleton bean,afterPropertiesSet会在容器启动时调用,destroy会在容器关闭时调用。而对于prototype bean,Spring容器在初始化bean并返回给客户端后就不再管理这个bean,所以destroy方法不会被调用。

# 2、使用@PostConstruct和@PreDestroy注解

@PostConstruct 和 @PreDestroy 注解是 JSR 250 规范提供的,Spring 支持这两个注解用于 Bean 的生命周期管理。@PostConstruct 注解的方法会在 Bean 完成初始化后被调用,而 @PreDestroy 注解的方法则会在 Bean 被销毁前调用。

下面是一个使用 @PostConstruct 和 @PreDestroy 注解的示例:

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

@Component
public class LifecycleBean {

    @PostConstruct
    public void init() {
        System.out.println("Bean is initialized");
    }

    @PreDestroy
    public void destroy() {
        System.out.println("Bean will be destroyed");
    }
}

在这个示例中,当 Spring 容器创建 LifecycleBean 的实例并完成初始化时,会调用 init 方法,你会看到 "Bean is initialized" 的输出。然后,当 Spring 容器关闭并销毁 LifecycleBean 的实例时,会调用 destroy 方法,你会看到 "Bean will be destroyed" 的输出。

注意,这些方法的调用时间取决于 Bean 的作用范围。对于 Singleton Bean,@PostConstruct 注解的方法会在容器启动时调用,@PreDestroy 注解的方法会在容器关闭时调用。而对于 Prototype Bean,Spring 容器在初始化 Bean 并返回给客户端后就不再管理这个 Bean,所以 @PreDestroy 注解的方法不会被调用。

另外,使用这两个注解需要注意的是,这两个注解标注的方法应该没有参数,并且返回类型为 void。

# 八、生命周期(Lifecycle)扩展

在 Spring 框架中,Lifecycle 接口是用于管理 Bean 生命周期的一个重要接口。它定义了一些方法,允许 Spring 容器在启动和关闭时通知 Bean,以便 Bean 可以执行相应的初始化或销毁操作。

Lifecycle 接口通常用于需要显式控制启动和停止行为的 Bean,例如后台任务、线程池、网络连接等。

# 1、Lifecycle 接口的定义

Lifecycle 接口位于 org.springframework.context 包中,定义如下:

public interface Lifecycle {

    // 启动组件
    void start();

    // 停止组件
    void stop();

    // 检查组件是否正在运行
    boolean isRunning();
}

# 1.1、方法说明

  • void start():启动组件。如果组件已经运行,则不会执行任何操作。
  • void stop():停止组件。如果组件已经停止,则不会执行任何操作。
  • boolean isRunning():检查组件是否正在运行。

# 2、Lifecycle 的使用场景

Lifecycle 接口适用于以下场景:

  • 后台任务:例如定时任务、消息监听器等,需要在 Spring 容器启动时启动,在容器关闭时停止。
  • 资源管理:例如数据库连接池、网络连接等,需要在容器启动时初始化,在容器关闭时释放资源。
  • 自定义组件:需要显式控制启动和停止行为的自定义组件。

# 3、实现 Lifecycle 接口的示例

以下是一个实现 Lifecycle 接口的简单示例,模拟一个后台任务:

# 4、示例代码

import org.springframework.context.Lifecycle;
import org.springframework.stereotype.Component;

@Component
public class BackgroundTask implements Lifecycle {

    private boolean running = false;

    @Override
    public void start() {
        if (!running) {
            System.out.println("BackgroundTask started!");
            running = true;
            // 启动后台任务
            new Thread(this::runTask).start();
        }
    }

    @Override
    public void stop() {
        if (running) {
            System.out.println("BackgroundTask stopped!");
            running = false;
            // 停止后台任务
        }
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    private void runTask() {
        while (running) {
            System.out.println("BackgroundTask is running...");
            try {
                Thread.sleep(1000); // 模拟任务执行
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

# 4.1、测试代码

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) throws InterruptedException {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 启动 Spring 容器
        context.start();

        // 模拟运行一段时间
        Thread.sleep(5000);

        // 关闭 Spring 容器
        context.stop();
        context.close();
    }
}

# 4.2、输出结果

BackgroundTask started!
BackgroundTask is running...
BackgroundTask is running...
BackgroundTask is running...
BackgroundTask is running...
BackgroundTask is running...
BackgroundTask stopped!

# 5、Lifecycle 的扩展接口

Spring 还提供了 Lifecycle 的扩展接口,用于更细粒度的生命周期控制:

# 5.1、SmartLifecycle

SmartLifecycle 是 Lifecycle 的扩展接口,提供了更丰富的生命周期控制功能,例如:

  • 自动启动:在 Spring 容器启动时自动调用 start() 方法。
  • 阶段控制:通过 getPhase() 方法定义组件的启动和停止顺序。
# a、示例代码
import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

@Component
public class SmartBackgroundTask implements SmartLifecycle {

    private boolean running = false;

    @Override
    public void start() {
        if (!running) {
            System.out.println("SmartBackgroundTask started!");
            running = true;
            new Thread(this::runTask).start();
        }
    }

    @Override
    public void stop() {
        if (running) {
            System.out.println("SmartBackgroundTask stopped!");
            running = false;
        }
    }

    @Override
    public boolean isRunning() {
        return running;
    }

    @Override
    public boolean isAutoStartup() {
        return true; // 自动启动
    }

    @Override
    public void stop(Runnable callback) {
        stop();
        callback.run(); // 通知容器停止完成
    }

    @Override
    public int getPhase() {
        return 0; // 定义启动和停止的顺序
    }

    private void runTask() {
        while (running) {
            System.out.println("SmartBackgroundTask is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                break;
            }
        }
    }
}

# 5.2、Phased

Phased 接口定义了 getPhase() 方法,用于控制组件的启动和停止顺序。SmartLifecycle 已经继承了 Phased。

# 6、Lifecycle 与 @PostConstruct 和 @PreDestroy 的区别

  • Lifecycle:用于显式控制组件的启动和停止行为,通常用于需要长时间运行的任务或资源管理。
  • @PostConstruct 和 @PreDestroy:用于在 Bean 初始化和销毁时执行特定的方法,通常用于简单的初始化和清理操作。

# 九、总结

在本文中,我们详细介绍了Spring Bean的生命周期以及如何扩展和定制Bean的生命周期。我们探讨了Bean后处理器、Bean工厂后处理器、自定义初始化方法和销毁回调、自定义作用域、替代装饰和条件化Bean注册等扩展方式。我们强调了灵活运用扩展机制的重要性,并通过示例代码和最佳实践建议帮助读者更好地理解和应用这些扩展方式。

通过深入了解和掌握Spring Bean的生命周期扩展,可以更好地定制和优化Spring应用。

祝你变得更强!

编辑 (opens new window)
#Spring容器初始化#Spring Bean生命周期
上次更新: 2025/04/01
Reactor 3指南
Spring容器:从依赖管理到注解配置全解析

← Reactor 3指南 Spring容器:从依赖管理到注解配置全解析→

最近更新
01
Spring Boot版本新特性
09-15
02
Spring框架版本新特性
09-01
03
Spring Boot开发初体验
08-15
更多文章>
Theme by Vdoing | Copyright © 2018-2025 京ICP备2021021832号-2 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式