深度解析 Spring 源码:探寻Bean的生命周期

2024-05-04 17:36

本文主要是介绍深度解析 Spring 源码:探寻Bean的生命周期,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

文章目录

    • 一、 Bean生命周期概述
    • 二、Bean生命周期流程图
    • 三、Bean生命周期验证
      • 3.1 代码案例
      • 3.2 执行结果
    • 四、Bean生命周期源码
      • 4.1 setBeanName()
      • 4.2 setBeanFactory()
      • 4.3 setApplicationContext()
      • 4.4 postProcessBeforeInitialization()
      • 4.5 afterPropertiesSet()
      • 4.6 postProcessAfterInitialization()
      • 4.7 destroy()

一、 Bean生命周期概述

Bean的生命周期包括了定义、实例化、初始化和销毁四个关键阶段,Spring框架在每个阶段都提供了钩子方法,允许开发者在特定的时机执行自定义的逻辑,从而实现对Bean生命周期的定制化管理。

  1. Bean的定义阶段: 在这个阶段,Spring会解析Bean的定义,包括从配置文件中读取Bean的元数据,例如类名、属性值、依赖关系等。这个阶段的主要目标是将Bean的定义加载到Spring的应用上下文中。
  2. Bean的实例化阶段: 一旦Bean的定义加载到容器中,Spring会根据这些定义创建Bean的实例。这可能涉及到通过构造函数或工厂方法创建实例,并将依赖项注入到Bean中。在这个阶段,Spring会创建Bean的原始对象,并将其放入容器中。
  3. Bean的初始化阶段: 在这个阶段,Spring会对Bean进行初始化。这包括执行任何在Bean实例化之后需要执行的定制逻辑,例如调用初始化方法、应用BeanPostProcessors等。这个阶段是在Bean实例创建完成后、在将Bean实例提供给应用程序之前执行的。
  4. Bean的销毁阶段: 最后一个阶段是Bean的销毁。在容器关闭或者特定的销毁时机触发时,Spring会调用Bean的销毁方法,执行清理工作,例如释放资源、关闭连接等。这个阶段是确保Bean在不再需要时能够正确地释放资源。

二、Bean生命周期流程图

在这里插入图片描述

Bean的生命周期执行步骤

  1. Bean实例化:当Spring容器启动时,它会创建Bean的实例。这通常是通过调用Bean的构造函数来完成的。
  2. Bean属性注入:在Bean实例化之后,Spring会进行属性注入。这是将外部数据或配置信息设置到Bean的属性中的过程。
  3. BeanNameAware接口的setBeanName方法调用:如果Bean实现了BeanNameAware接口,那么在Bean被初始化之前,Spring会调用其setBeanName方法,并传递给它一个字符串,表示Bean的名称。
  4. BeanFactoryAware接口的setBeanFactory方法调用:如果Bean实现了BeanFactoryAware接口,那么在Bean被初始化之前,Spring会调用其setBeanFactory方法,并传递给它一个BeanFactory对象,以便Bean可以访问工厂的其他Bean。(同理~调用ApplicationContextAware接口的setApplicationContext()方法)
  5. BeanPostProcessor接口的初始化之前方法调用:在Bean的属性注入之后,但在初始化之前,Spring将调用BeanPostProcessor接口的postProcessBeforeInitialization方法来对bean执行一些额外的操作。
  6. InitializingBean接口的afterPropertiesSet方法调用:如果Bean实现了InitializingBean接口,并且在它的afterPropertiesSet方法中被调用之前,Spring会尝试对其进行属性注入。
  7. BeanPostProcessor接口的初始化之前方法调用:在Bean的属性注入之后,但在初始化之后,Spring将调用BeanPostProcessor接口的postProcessAfterInitialization方法来对bean执行一些额外的操作。
  8. Bean正常使用:在Bean完成所有必要的初始化之后,它就可以被使用了。这时,应用程序可以通过依赖注入或其他方式获取Bean的引用,并进行相应的操作。
  9. DisposableBean接口的destroy方法调用:当Spring容器关闭时,它会销毁Bean。如果Bean实现了DisposableBean接口,那么在Bean被销毁之前,Spring会调用其destroy方法。
  10. 自定义销毁方法调用:除了上面的标准方法外,还可以为Bean定义自定义的销毁方法,并在容器关闭时自动调用。

三、Bean生命周期验证

本文使用 Spring Framework 的注解来描述一个完整的 Bean 生命周期。Bean 的完整生命周期,包括创建、初始化、使用和销毁。

3.1 代码案例

演示 Bean 的完整生命周期Demo

  1. 配置类AppConfig 类使用 @Configuration 注解定义 Spring 配置类,并声明了一个 Bean。
package com.example.springdemo.bean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic MyBean myBeanDemo() {return new MyBean();}
}
  1. Bean 类MyBean 类是我们要管理的 Bean。它包含一个 @PostConstruct 注解的 init() 方法,该方法将在 Bean 初始化后立即执行。此外,它还包含一个 @PreDestroy 注解的 destroy() 方法,该方法将在 Bean 销毁前执行。
package com.example.springdemo.bean;import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;@Component
public class MyBean implements BeanNameAware, BeanFactoryAware,ApplicationContextAware, InitializingBean, DisposableBean {public MyBean() {System.out.println("Bean 构造函数调用...");}@PostConstructpublic void init() {System.out.println("Bean 初始化...");}@PreDestroypublic void destroy() {System.out.println("Bean 销毁...");}public void performTask() {System.out.println("Bean 正在执行任务...");}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("Bean 获得所在BeanFactory引用...");}@Overridepublic void setBeanName(String s) {System.out.println("Bean 名称...");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("Bean 属性设置之后,自定义的初始化...");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {System.out.println("Bean 获得所在ApplicationContext引用...");}
}
  1. Main 类Main 类是主程序入口,创建 Spring 应用程序上下文,获取 Bean 实例,并在使用完 Bean 后关闭上下文。
package com.example.springdemo;import com.example.springdemo.bean.AppConfig;
import com.example.springdemo.bean.MyBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;@SpringBootApplication
public class SpringDemoApplication {public static void main(String[] args) {SpringApplication.run(SpringDemoApplication.class, args);// 创建 Spring 应用程序上下文AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取 MyBean 实例MyBean bean = context.getBean(MyBean.class);// 使用 Beanbean.performTask();// 关闭上下文context.close();}
}

3.2 执行结果

在这里插入图片描述

四、Bean生命周期源码

需要调试运行看Bean生命周期的读者可自行尝试哈,本文主要解读部分相对重要的源码,亲测一直nextStep,根本点不完-_-,头昏眼花,哈哈哈哈我是菜鸡

4.1 setBeanName()

Bean 实现了 BeanNameAware 接口时,容器在初始化 Bean 时会调用其 setBeanName() 方法,从而允许 Bean 在初始化阶段获取自己在容器中的名字。

在这里插入图片描述

4.2 setBeanFactory()

BeanFactoryAware 接口允许一个 Bean 在初始化阶段获得对自己所在的 BeanFactory 的引用,从而可以与容器进行交互,例如动态地获取其他 Bean 实例或执行特定的逻辑。

在这里插入图片描述

4.3 setApplicationContext()

ApplicationContextAware 接口允许一个 Bean 在初始化阶段获得对自己所在的 ApplicationContext 的引用,从而可以与容器进行交互,例如动态地获取其他 Bean 实例或执行特定的逻辑。 (细心的读者发现这个视乎和前面类似,读者可看我前面的文章,有细说BeanFactory 和ApplicationContext 的区别)

在这里插入图片描述

4.4 postProcessBeforeInitialization()

BeanPostProcessor 接口定义了两个默认方法,分别用于在初始化 Bean 之前和之后对其进行一些自定义处理,但默认情况下不对 Bean 进行修改。

在这里插入图片描述

4.5 afterPropertiesSet()

InitializingBean 接口定义了一个方法 afterPropertiesSet(),用于在 Bean 的属性设置之后执行自定义的初始化逻辑。

在这里插入图片描述

4.6 postProcessAfterInitialization()

BeanPostProcessor 接口定义了两个默认方法,分别用于在初始化 Bean 之前和之后对其进行一些自定义处理,但默认情况下不对 Bean 进行修改。 (与4.4相同,只是调用的顺序不同,结合一起看哈)

在这里插入图片描述

4.7 destroy()

Bean准备就绪,可被应用程序使用,且一直驻留在应用上下文中,直到应用上下文被销毁。 DisposableBean 接口定义了一个方法 destroy(),用于在 Bean 销毁之前执行自定义的清理逻辑。

在这里插入图片描述

ps:想要了解各个方法的实现类的读者可自行解读相应的源码。

知识象烛光,能照亮一个人,也能照亮无数人

这篇关于深度解析 Spring 源码:探寻Bean的生命周期的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/959742

相关文章

Java实现检查多个时间段是否有重合

《Java实现检查多个时间段是否有重合》这篇文章主要为大家详细介绍了如何使用Java实现检查多个时间段是否有重合,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录流程概述步骤详解China编程步骤1:定义时间段类步骤2:添加时间段步骤3:检查时间段是否有重合步骤4:输出结果示例代码结语作

Java中String字符串使用避坑指南

《Java中String字符串使用避坑指南》Java中的String字符串是我们日常编程中用得最多的类之一,看似简单的String使用,却隐藏着不少“坑”,如果不注意,可能会导致性能问题、意外的错误容... 目录8个避坑点如下:1. 字符串的不可变性:每次修改都创建新对象2. 使用 == 比较字符串,陷阱满

Java判断多个时间段是否重合的方法小结

《Java判断多个时间段是否重合的方法小结》这篇文章主要为大家详细介绍了Java中判断多个时间段是否重合的方法,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录判断多个时间段是否有间隔判断时间段集合是否与某时间段重合判断多个时间段是否有间隔实体类内容public class D

IDEA编译报错“java: 常量字符串过长”的原因及解决方法

《IDEA编译报错“java:常量字符串过长”的原因及解决方法》今天在开发过程中,由于尝试将一个文件的Base64字符串设置为常量,结果导致IDEA编译的时候出现了如下报错java:常量字符串过长,... 目录一、问题描述二、问题原因2.1 理论角度2.2 源码角度三、解决方案解决方案①:StringBui

Java覆盖第三方jar包中的某一个类的实现方法

《Java覆盖第三方jar包中的某一个类的实现方法》在我们日常的开发中,经常需要使用第三方的jar包,有时候我们会发现第三方的jar包中的某一个类有问题,或者我们需要定制化修改其中的逻辑,那么应该如何... 目录一、需求描述二、示例描述三、操作步骤四、验证结果五、实现原理一、需求描述需求描述如下:需要在

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2