Spring 应用上下文探秘:生命周期解析与最佳实践

欢迎来到我的博客,代码的世界里,每一行都是一个故事


在这里插入图片描述

Spring 应用上下文探秘:生命周期解析与最佳实践

    • 前言
    • 应用上下文的初始化过程
      • 1. 应用上下文的初始化过程:
      • 2. 不同类型的 ApplicationContext 初始化流程:
        • 2.1 AnnotationConfigApplicationContext:
        • 2.2 ClassPathXmlApplicationContext:
        • 2.3 GenericApplicationContext:
      • 3. 初始化流程的特点
    • BeanPostProcessor 与 BeanFactoryPostProcessor
      • BeanPostProcessor
        • 定义与作用:
        • 生命周期中的调用时机:
      • BeanFactoryPostProcessor
        • 定义与作用:
        • 生命周期中的调用时机:
      • 比较
      • 举例
    • bean生命周期中的事件
      • 1. Bean 生命周期中的事件:
      • 2. Spring 事件机制的简介:
      • 3. 自定义事件的实现与触发:
        • 3.1 创建自定义事件类:
        • 3.2 创建自定义事件监听器:
        • 3.3 触发自定义事件:
    • 动态刷新和关闭应用上下文
      • 1. 刷新 ApplicationContext 的过程:
      • 2. 优雅关闭 Spring Boot 应用:

前言

在 Spring 的世界中,每个 bean 都有其自己的生命周期,就像每个角色都有自己的故事一样。今天,我们将成为 Spring 的探险者,深入探索应用上下文的生命周期,解开其中的神秘面纱。或许,你将在这段旅程中发现一些你从未见过的 Spring 魔法。

应用上下文的初始化过程

Spring 中的 ApplicationContext 是 Spring 框架中用于管理 Bean 的核心容器。它负责加载、配置和管理 Bean,以及提供其他高级功能。ApplicationContext 的初始化过程和不同类型的 ApplicationContext 初始化流程如下:

1. 应用上下文的初始化过程:

ApplicationContext 的初始化主要包括以下几个阶段:

  1. 资源定位(Resource Loading):
    ApplicationContext 首先会通过资源定位器(ResourceLoader)来加载配置文件或者其他资源。这些资源可以是 XML 配置文件、Java 配置类、注解等。

  2. 资源解析(Resource Parsing):
    一旦资源加载完成,ApplicationContext 将使用相应的资源解析器(如 XmlBeanDefinitionReader、AnnotationConfigApplicationContext、GenericApplicationContext 等)来解析这些资源。解析的结果是一组 BeanDefinition,其中包含了 Bean 的定义信息。

  3. Bean 的注册(Bean Registration):
    解析完成后,ApplicationContext 将解析得到的 BeanDefinition 注册到内部的 BeanFactory 中。BeanFactory 是 ApplicationContext 的基础,负责管理 Bean 的生命周期、依赖关系等。

  4. Bean 的实例化和初始化(Bean Instantiation and Initialization):
    当应用程序首次请求某个 Bean 的时候,BeanFactory 会负责实例化和初始化该 Bean。这包括调用构造函数、设置属性、调用初始化方法等。

  5. Bean 的生命周期管理(Bean Lifecycle Management):
    ApplicationContext 负责监控 Bean 的生命周期,包括调用 Bean 的初始化方法和销毁方法。在 Bean 的整个生命周期中,ApplicationContext 可以触发各种事件。

2. 不同类型的 ApplicationContext 初始化流程:

2.1 AnnotationConfigApplicationContext:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AppConfig.class);
context.refresh();
  • register(AppConfig.class):注册配置类。
  • refresh():刷新容器,触发容器的初始化。
2.2 ClassPathXmlApplicationContext:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
  • ClassPathXmlApplicationContext("applicationContext.xml"):通过 XML 文件初始化容器。
2.3 GenericApplicationContext:
GenericApplicationContext context = new GenericApplicationContext();
new XmlBeanDefinitionReader(context).loadBeanDefinitions("applicationContext.xml");
context.refresh();
  • GenericApplicationContext():创建 GenericApplicationContext 对象。
  • new XmlBeanDefinitionReader(context).loadBeanDefinitions("applicationContext.xml"):通过 XmlBeanDefinitionReader 加载 XML 文件。
  • context.refresh():刷新容器。

3. 初始化流程的特点

  • 灵活性:Spring 提供了多种类型的 ApplicationContext 实现,以适应不同的应用场景。
  • 层级结构:可以有多个 ApplicationContext 实例,形成父子关系,子容器可以访问父容器中的Bean。
  • 事件机制:Spring 提供了丰富的事件机制,允许Bean监听容器事件,如上下文刷新或关闭。

BeanPostProcessor 与 BeanFactoryPostProcessor

在 Spring 框架中,BeanPostProcessorBeanFactoryPostProcessor 是两种强大的扩展点,允许开发者在 Spring 容器实例化 Bean 之前后以及创建和初始化 Bean 工厂之后进行额外的处理。

BeanPostProcessor

定义与作用:
  • BeanPostProcessor 接口定义了回调方法,这些方法在 Spring 容器初始化 Bean 之前后被调用。
  • 它主要用于对 Bean 实例进行一些自定义处理,比如检查 Bean 属性的正确性,或者使用代理包装 Bean。
生命周期中的调用时机:
  • BeanPostProcessorpostProcessBeforeInitialization 方法在 Bean 的初始化方法(如 @PostConstruct 注解的方法或者 init-method 定义的方法)之前被调用。
  • postProcessAfterInitialization 方法在 Bean 的初始化方法之后被调用。

BeanFactoryPostProcessor

定义与作用:
  • BeanFactoryPostProcessor 是一个用于修改应用上下文的工厂配置的工厂后置处理器。它主要用于在容器实例化任何 Bean 之前读取配置元数据,并可能修改它。
  • 它可以修改或添加 Bean 定义信息,也常用于处理自定义配置文件。
生命周期中的调用时机:
  • BeanFactoryPostProcessor 在容器加载了 Bean 的定义信息之后,在 Bean 实例化之前被调用。
  • 这意味着 BeanFactoryPostProcessor 在所有的 Bean 定义都已加载到容器中,但还没有实例化任何 Bean 时执行。

比较

  • 执行时间BeanFactoryPostProcessor 在容器启动阶段执行,处理 Bean 定义;BeanPostProcessor 在容器创建 Bean 时执行,处理 Bean 实例。
  • 作用范围BeanFactoryPostProcessor 对整个 Bean 工厂生效,可影响所有 Bean 定义;BeanPostProcessor 主要影响单个 Bean 实例。

举例

  • 使用 BeanFactoryPostProcessor 可以修改 Bean 定义,例如修改某个 Bean 的属性值。
  • 使用 BeanPostProcessor 可以在 Bean 初始化前后执行一些操作,例如使用 AOP 代理包装一个对象。

在 Spring 的生命周期中,这两个接口的正确使用可以大大增强应用的灵活性和可配置性。

bean生命周期中的事件

在 Spring 框架中,Bean 的生命周期中包含了一系列事件,开发者可以通过 Spring 的事件机制监听和处理这些事件。以下是关于 Bean 生命周期中的事件和 Spring 事件机制的简介,以及如何实现和触发自定义事件:

1. Bean 生命周期中的事件:

在 Bean 的生命周期中,主要涉及到以下几个事件:

  1. 实例化前事件(Before Instantiation):
    在 Bean 的实例化之前触发,允许定制 Bean 的实例化过程。

  2. 实例化后事件(After Instantiation):
    在 Bean 的实例化之后触发,可以对实例进行进一步的定制。

  3. 属性设置事件(Property Set):
    在 Bean 的属性设置(注入)阶段触发,允许对属性进行额外的处理。

  4. 初始化前事件(Before Initialization):
    在 Bean 的初始化之前触发,常用于执行一些初始化前的逻辑。

  5. 初始化后事件(After Initialization):
    在 Bean 的初始化之后触发,通常用于执行一些初始化后的逻辑。

  6. 销毁前事件(Before Destruction):
    在 Bean 被销毁之前触发,允许执行一些清理操作。

2. Spring 事件机制的简介:

Spring 事件机制基于观察者模式,其中有两个核心接口:ApplicationEventApplicationListener

  • ApplicationEvent:定义了事件对象的基本结构,通常通过继承该接口创建自定义事件。
  • ApplicationListener:监听器接口,实现该接口的类可以处理特定类型的事件。

Spring 的 ApplicationEventPublisher 接口负责发布事件,而 ApplicationEventMulticaster 负责将事件传递给注册的监听器。

3. 自定义事件的实现与触发:

3.1 创建自定义事件类:
import org.springframework.context.ApplicationEvent;public class CustomEvent extends ApplicationEvent {private String eventData;public CustomEvent(Object source, String eventData) {super(source);this.eventData = eventData;}public String getEventData() {return eventData;}
}
3.2 创建自定义事件监听器:
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {@Overridepublic void onApplicationEvent(CustomEvent event) {System.out.println("Received custom event: " + event.getEventData());}
}
3.3 触发自定义事件:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;@Component
public class EventPublisher {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void publishCustomEvent(String eventData) {CustomEvent customEvent = new CustomEvent(this, eventData);eventPublisher.publishEvent(customEvent);}
}

在上述代码中,EventPublisher 类通过 ApplicationEventPublisher 发布自定义事件 CustomEvent,而 CustomEventListener 则监听并处理该自定义事件。

这样,当你调用 EventPublisherpublishCustomEvent 方法时,会触发自定义事件,监听器将收到并处理该事件。

动态刷新和关闭应用上下文

1. 刷新 ApplicationContext 的过程:

刷新 ApplicationContext 是指在应用程序运行时,重新加载配置、重新实例化 Bean,并刷新内部状态。在 Spring 中,刷新 ApplicationContext 的主要过程包括以下几个步骤:

  1. 创建并配置 ConfigurableApplicationContext:
    在应用程序启动时,首先创建一个 ConfigurableApplicationContext 的实例,并进行配置。这可以通过不同的 ApplicationContext 实现类,如 GenericApplicationContext、AnnotationConfigApplicationContext、ClassPathXmlApplicationContext 等。

  2. 注册 Bean 定义:
    将配置的 Bean 定义(BeanDefinition)注册到 ApplicationContext 中。这些定义可以通过 XML 配置文件、Java 配置类或注解来指定。

  3. 刷新 ApplicationContext:
    调用 ConfigurableApplicationContext 的 refresh() 方法触发 ApplicationContext 的刷新过程。在这个过程中,将会实例化和初始化所有的 Bean,并解析各种依赖关系。

  4. 发布刷新事件:
    在刷新过程完成后,ApplicationContext 会发布刷新事件,通知所有注册的监听器(如事件监听器)。

  5. 完成刷新过程:
    ApplicationContext 完成了刷新过程,此时应用程序已经处于运行状态,可以开始处理请求等操作。

2. 优雅关闭 Spring Boot 应用:

Spring Boot 提供了一种优雅关闭应用程序的机制,确保在应用关闭时执行一些清理工作。以下是实现优雅关闭的步骤:

  1. 实现 DisposableBean 接口或定义自定义销毁方法:
    在需要进行清理工作的 Bean 上实现 DisposableBean 接口,或者在 Bean 上使用 @PreDestroy 注解定义自定义销毁方法。

    import org.springframework.beans.factory.DisposableBean;public class MyBean implements DisposableBean {@Overridepublic void destroy() throws Exception {// 执行清理工作}
    }
    
  2. 注册关闭钩子(Shutdown Hook):
    在 Spring Boot 应用程序中,可以注册关闭钩子,确保在关闭时执行清理操作。通常,这可以通过在主类中调用 SpringApplication.addShutdownHook(true) 实现。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
    public class MyApplication {public static void main(String[] args) {SpringApplication app = new SpringApplication(MyApplication.class);app.addShutdownHook(true);app.run(args);}
    }
    
  3. 使用 Actuator 进行关闭:
    Spring Boot Actuator 提供了一组 REST 端点,包括 /actuator/shutdown,可以通过发送 POST 请求到该端点来关闭应用程序。

    首先,确保在 application.propertiesapplication.yml 中开启 shutdown 端点:

    management.endpoints.web.exposure.include=shutdown
    

    然后,可以通过发送 POST 请求到 /actuator/shutdown 端点来关闭应用程序:

    curl -X POST http://localhost:8080/actuator/shutdown
    

通过上述步骤,你可以在应用程序关闭时执行清理操作,确保资源被正确释放。这对于处理数据库连接、缓存、消息队列等资源非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/607775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

湖南大学-数据库系统-2018期末考试解析

【写在前面】 这是2018年的卷子&#xff0c;复习备考的时候做了并与同学校对了答案。答案仅供参考。这张难度不大&#xff0c;同样的&#xff0c;跟前几张差不了太多。但是从这一年开始&#xff0c;选择题变成了15道&#xff0c;越来越贴切近几年的考试了。 一、单选题&#xf…

HTML JavaScript 康威生命游戏

<!DOCTYPE html> <html> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>康威生命游戏</title><style>body {font-family: Arial, sa…

JS-基础语法(一)

JavaScript简单介绍 变量 常量 数据类型 类型转换 案例 1.JavaScript简单介绍 JavaScript 是什么&#xff1f; 是一种运行在客户端&#xff08;浏览器&#xff09;的编程语言&#xff0c;可以实现人机交互效果。 JS的作用 JavaScript的组成 JSECMAScript( 基础语法 )…

每日算法打卡:分巧克力 day 9

文章目录 原题链接题目描述输入格式输出格式数据范围输入样例&#xff1a;输出样例&#xff1a; 题目分析示例代码 原题链接 1227. 分巧克力 题目难度&#xff1a;简单 题目来源&#xff1a;第八届蓝桥杯省赛C A/B组,第八届蓝桥杯省赛Java A/B/C组 题目描述 儿童节那天有 …

【2024系统架构设计】 系统架构设计师第二版-嵌入式系统架构设计理论与实践

目录 一 嵌入式系统软件架构的原理 二 嵌入式系统软件架构的设计方法 三 案例分析 一 嵌入式系统软件架构的原理 🚀嵌入式系统的典型架构可以分为

java.lang.ClassNotFoundException: jakarta.servlet.Servlet

联系servlet的使用时&#xff0c;编写了servlet的处理器&#xff0c;但是浏览器报500错误&#xff0c;有时候是404错误 WebServlet("/mayikt") public class Servlet1 implements Servlet {Overridepublic void init(ServletConfig servletConfig) throws ServletExc…

C++实现简单贪吃蛇游戏

文章目录 1 开发历程2 开发思路3 使用介绍4 源文件代码5 游戏截图6 小结 1 开发历程 游戏使用C语言开发&#xff0c;是博主某个下午心血来潮的结果&#xff0c;后面又花了点时间加了计分&#xff0c;记录历史得分的功能。 2 开发思路 其实贪吃蛇主要难在蛇身的移动上&#x…

cocos creator 如何绑定参数到编辑器

很多cocos creator同学不知道如何绑定组件属性到编辑器上&#xff0c;今天我们来教大家如何绑定 1: 基本数据属性绑定到编辑器 这个非常简单&#xff0c;模板是属性名字: 默认的值; Is_debug: false, speed: 100, 2: 系统组件类型与节点绑定到编辑器 属性名字: { type: 组件…

代码随想录刷题第四十三天| 1049. 最后一块石头的重量 II ● 494. 目标和 ● 474.一和零

代码随想录刷题第四十三天 今天为三道0-1背包问题的变种&#xff0c; 分别有三个小问题 给定一个容量为j的背包&#xff0c;尽可能装下物品&#xff0c;找到能装下物品的最大价值 dp[i][j] max(dp[i-1][j], dp[i-1][j-nums[i]]nums[i]) 给定一个容量为j的背包&#xff0c;找…

VScode/Xshell连接学校服务器

vscode连学校服务器 1.连接atrust VPN2.Xshell连接服务器2.1创建一个自己的用户 3.xftp传文件4.vscode连接服务器4.1下载remote-ssh4.2连接服务器4.3激活conda环境4.4运行代码 5. pytorch版本不兼容解决方案 1.连接atrust VPN 如果是使用的是校园网&#xff0c;可以不连接 2…

【全栈开发|Fresh框架】Fresh环境安装与快速体验Fresh全栈开发

文章目录 前言一、环境配置1. 安装Deno2. 安装idea插件 二、Hello World1.创建项目2.项目结构3. 创建一个路由4. 创建一个动态路由5. 自定义handlers1. 自定义响应头2. 随即生成uuid 6. 表单提交7. 部署到生产环境1. 将代码上传到github2. 在Deno控制面板创建一个项目 总结 前言…

面试算法100:三角形中最小路径之和

题目 在一个由数字组成的三角形中&#xff0c;第1行有1个数字&#xff0c;第2行有2个数字&#xff0c;以此类推&#xff0c;第n行有n个数字。例如&#xff0c;下图是一个包含4行数字的三角形。如果每步只能前往下一行中相邻的数字&#xff0c;请计算从三角形顶部到底部的路径经…

强烈推荐!这8款在线画图工具好用极了

即时设计 即时设计作为一种简单的绘图工具&#xff0c;为创作者提供了一个方便而强大的创作平台&#xff0c;具有丰富的绘图工具、实时合作、矢量绘图和组件设计系统等功能。即时设计可以满足不同的创作需求&#xff0c;使创意自由流动。 强大的矢量编辑工具 即时设计提供了…

苹果电脑Markdown文本编辑Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

C++每日一练(14):对称矩阵的判定

题目描述 输入矩阵的行数&#xff0c;再依次输入矩阵的每行元素&#xff0c;判断该矩阵是否为对称矩阵&#xff0c;若矩阵对称输出“yes"&#xff0c;不对称输出”no“。 输入 第一行输入一个正整数N&#xff08;N<20&#xff09;&#xff0c;表示矩阵的行数&#xff0…

网络通信(12)-C#TCP客户端封装帮助类实例

本文使用Socket在C#语言环境下完成TCP客户端封装帮助类的实例。 实例完成的功能: 客户端与服务器连接,实现实时刷新状态。 客户端接收服务器的数据。 客户端发送给服务器的数据。 客户端实时判定状态,断开连接后自动重连。 客户端与服务器端发送心跳包。 在VS中创建C…

IntelliJ IDEA 如何编译 Maven 工程项目

在当今的Java开发领域&#xff0c;Maven已经成为项目构建和依赖管理的标准工具。IntelliJ IDEA作为一款集成度高的Java开发环境&#xff0c;提供了许多强大的功能来简化和优化Maven项目的构建流程。本文将深入介绍如何使用IntelliJ IDEA编译Maven工程的详细步骤以及一些高级技巧…

Lumerical Monitors------ Global properties

Lumerical Monitors------ Global properties Global properties 全局属性 Global properties 全局属性 在 Lumerical 中&#xff0c;这里以 FDTD 工程文件举例&#xff0c;所有的 monitors 都可以通过上方选项卡中的 monitor 标签页添加。 注意上面有一个 Global properties…

MS3814:DVI/HDMI TMDS FR-4 和电缆均衡器/驱动器

产品简述 MS3814 是一款 TMDS 均衡 / 驱动器芯片&#xff0c;用于补偿 FR-4 和 电缆到 DVI/HDMI 连接器的损耗。提供完全满足 DVI/HDMI TMDS 要求的输出。芯片还可用于 DVI/HDMI 电缆以延长传输距离&#xff0c;提 高连接器接收侧电缆通道的抖动余量。片上 TMDS…

Prometheus 与 VictoriaMetrics对比

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 时序数据库有很多&#xff0c;比如Prometheus、M3DB、TimescaleDB、OpenTSDB、InfluxDB等等。Prometheus和VictoriaMetrics是开源的时间序列数据库&#xff0c;在复杂的环境中提供了强大…