Bean如何诞生与消亡:生命周期探秘【beans 二】

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


在这里插入图片描述

Bean如何诞生与消亡:生命周期探秘【beans 二】

    • 前言
    • bean的创建过程
    • bean的初始化阶段
      • 1. 实现InitializingBean接口:
      • 2. 使用@PostConstruct注解:
    • bean的属性注入
      • 1. Setter注入:
      • 2. 使用@Autowired注解:
    • 自定义初始化方法
    • bean的销毁阶段
      • 1. 实现DisposableBean接口:
      • 2. 使用@PreDestroy注解:
    • 手动销毁bean
    • 生命周期回调顺序
      • 初始化阶段:
      • 销毁阶段:
      • 总体顺序:

前言

在软件开发的世界中,每个对象都有其生命周期,而Spring中的Bean也不例外。Bean的生命周期管理是Spring框架的一项关键功能,它确保了在应用程序运行过程中,每个Bean都能在适当的时候被创建、初始化,并在不再需要的时候被优雅地销毁。本文将以代码为线索,带领你深入探讨Spring Bean的生命周期,让你对Spring框架有更深刻的认识。

bean的创建过程

Bean的创建过程通常是由Spring容器来管理的,其中包括实例化Bean和调用构造函数等步骤。以下是简要的Bean创建过程:

  1. 实例化Bean: Spring容器负责实例化Bean,这是通过使用Java反射机制来完成的。它会查找并加载Bean的类,然后使用newInstance()方法来创建Bean的实例。
// 示例Bean类
public class MyBean {public MyBean() {// 构造函数}
}
  1. 属性注入: 一旦Bean实例被创建,Spring容器会注入所需的属性。这可以通过构造函数注入、Setter方法注入或字段注入来实现。
// 示例Bean类,通过构造函数注入属性
public class MyBean {private String name;public MyBean(String name) {this.name = name;}// Getter和Setter方法可以用于属性的访问和修改// ...
}
  1. 初始化回调: 如果Bean实现了InitializingBean接口或在配置文件中定义了初始化方法,Spring容器将调用该方法执行一些初始化操作。
// 示例Bean类,实现InitializingBean接口
import org.springframework.beans.factory.InitializingBean;public class MyBean implements InitializingBean {@Overridepublic void afterPropertiesSet() throws Exception {// 在这里执行初始化操作}
}
  1. Bean的使用: 完成初始化后,Bean就可以被应用程序的其他部分使用了。
// 示例Bean的使用
MyBean myBean = applicationContext.getBean(MyBean.class);

这就是简单的Bean创建过程。在实际项目中,Bean的创建可能涉及更多的细节,例如Bean的作用域、生命周期等,但上述步骤是基本的创建过程。请注意,以上示例中的代码是为了说明概念,实际项目中可能需要根据具体情况进行适当的调整。

bean的初始化阶段

在Spring中,Bean的初始化阶段可以通过实现InitializingBean接口或使用@PostConstruct注解来完成。以下是这两种方法的示例:

1. 实现InitializingBean接口:

通过实现InitializingBean接口,你可以覆盖afterPropertiesSet方法,在该方法中执行Bean的初始化逻辑。

import org.springframework.beans.factory.InitializingBean;public class MyBean implements InitializingBean {private String name;// 其他属性和方法省略@Overridepublic void afterPropertiesSet() throws Exception {// 在这里执行Bean的初始化逻辑System.out.println("Bean初始化逻辑执行中...");}
}

2. 使用@PostConstruct注解:

通过使用@PostConstruct注解,你可以在方法上添加该注解,标识该方法应该在Bean的初始化阶段被调用。

import javax.annotation.PostConstruct;public class MyBean {private String name;// 其他属性和方法省略@PostConstructpublic void init() {// 在这里执行Bean的初始化逻辑System.out.println("Bean初始化逻辑执行中...");}
}

在上述两种方法中,当Spring容器实例化Bean并设置好属性之后,它会检测Bean是否实现了InitializingBean接口或是否有使用了@PostConstruct注解的初始化方法。如果是,容器将在适当的时候调用这些初始化方法。

选择使用哪种方式取决于个人或团队的偏好,通常来说,使用@PostConstruct注解更为灵活,并且不依赖于Spring的特定接口。

bean的属性注入

在Spring中,Bean的属性注入可以通过使用Setter方法和@Autowired注解来实现。以下是这两种方法的示例:

1. Setter注入:

通过Setter方法注入属性,你可以为Bean类提供Setter方法,Spring容器将使用这些方法来设置Bean的属性。

public class MyBean {private String name;// 其他属性和方法省略// Setter方法用于注入name属性public void setName(String name) {this.name = name;}
}

2. 使用@Autowired注解:

通过使用@Autowired注解,你可以在属性上或Setter方法上标记注入点,Spring容器会自动在初始化Bean时注入相关的依赖。

import org.springframework.beans.factory.annotation.Autowired;public class AnotherBean {private MyBean myBean;// 其他属性和方法省略// 使用@Autowired注解进行属性注入@Autowiredpublic void setMyBean(MyBean myBean) {this.myBean = myBean;}
}

在上述两种方法中,Spring容器会检测Bean的属性(通过Setter方法或使用@Autowired注解的属性),并在初始化Bean时注入相应的值或依赖。

选择使用哪种方式通常取决于个人或团队的偏好,以及具体的业务场景。使用Setter注入更为传统,而使用@Autowired注解通常更为简洁。在实际项目中,你可能会选择两者结合使用,根据需要进行灵活配置。

自定义初始化方法

在Spring中,除了使用InitializingBean接口和@PostConstruct注解外,还可以通过自定义初始化方法来完成Bean的初始化。这个方法需要在Spring配置文件或Java配置类中进行定义。以下是一个示例:

public class MyBean {private String name;// 其他属性和方法省略// 自定义初始化方法public void customInit() {// 在这里执行自定义的初始化逻辑System.out.println("执行自定义初始化方法...");}
}

在XML配置文件中,你可以使用<bean>元素的init-method属性来指定自定义初始化方法:

<bean id="myBean" class="com.example.MyBean" init-method="customInit"><!-- 其他配置属性 -->
</bean>

在Java配置类中,你可以使用@Bean注解的initMethod属性:

@Configuration
public class AppConfig {@Bean(initMethod = "customInit")public MyBean myBean() {return new MyBean();}
}

在这个示例中,customInit方法会在Bean被实例化并设置完属性后被调用。你可以在这个方法中执行一些自定义的初始化逻辑。

注意:如果一个Bean同时实现了InitializingBean接口、使用了@PostConstruct注解和自定义初始化方法,它们都会被调用。但建议选择其中一种方式,以保持代码的简洁性和一致性。

bean的销毁阶段

在Spring中,Bean的销毁阶段可以通过实现DisposableBean接口或使用@PreDestroy注解来完成。以下是这两种方法的示例:

1. 实现DisposableBean接口:

通过实现DisposableBean接口,你可以覆盖destroy方法,在该方法中执行Bean的销毁逻辑。

import org.springframework.beans.factory.DisposableBean;public class MyBean implements DisposableBean {private String name;// 其他属性和方法省略@Overridepublic void destroy() throws Exception {// 在这里执行Bean的销毁逻辑System.out.println("Bean销毁逻辑执行中...");}
}

2. 使用@PreDestroy注解:

通过使用@PreDestroy注解,你可以在方法上添加该注解,标识该方法应该在Bean的销毁阶段被调用。

import javax.annotation.PreDestroy;public class MyBean {private String name;// 其他属性和方法省略@PreDestroypublic void customDestroy() {// 在这里执行Bean的销毁逻辑System.out.println("Bean销毁逻辑执行中...");}
}

在上述两种方法中,当Spring容器关闭时,它会检测Bean是否实现了DisposableBean接口或是否有使用了@PreDestroy注解的销毁方法。如果是,容器将在适当的时候调用这些销毁方法。

选择使用哪种方式通常取决于个人或团队的偏好,以及具体的业务场景。使用DisposableBean接口是一种标准的Spring方式,而@PreDestroy注解通常更为简洁。在实际项目中,你可能会选择两者结合使用,根据需要进行灵活配置。

手动销毁bean

在Spring中,你可以手动销毁Bean通过调用ApplicationContextclose方法。当你关闭应用程序上下文时,Spring容器将销毁所有已经初始化的Bean。

以下是一个简单的示例:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainApp {public static void main(String[] args) {// 创建应用程序上下文AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);// 获取Bean实例MyBean myBean = context.getBean(MyBean.class);// 使用Bean...// 手动销毁Bean,关闭应用程序上下文context.close();}
}

在上述示例中,当调用context.close()时,Spring容器将销毁所有已经初始化的Bean,包括执行销毁方法(如果Bean实现了DisposableBean接口或使用了@PreDestroy注解)。

这种方式适用于独立应用程序,但在Web应用程序中,通常是通过容器(如Tomcat)来管理应用程序上下文的生命周期。在这种情况下,你不需要手动调用close方法,而是由容器负责销毁Bean。

请注意,在某些情况下,Spring容器可能无法自动感知到应用程序的关闭,因此手动调用close方法是一种确保销毁Bean的可靠方式。

生命周期回调顺序

在Spring中,Bean的生命周期回调方法包括初始化和销毁阶段。以下是不同生命周期回调方法的执行顺序:

初始化阶段:

  1. 构造函数(Constructor): Bean的构造函数首先被调用,创建Bean的实例。

  2. 属性注入(Setter注入、字段注入等): Spring容器注入Bean的属性,包括通过构造函数注入和Setter注入。

  3. 实现InitializingBean接口的afterPropertiesSet方法: 如果Bean实现了InitializingBean接口,Spring容器会在属性注入后调用afterPropertiesSet方法进行初始化。

  4. 使用@PostConstruct注解的方法: 如果Bean中有使用了@PostConstruct注解的方法,这些方法会在上述步骤完成后被调用。

销毁阶段:

  1. 实现DisposableBean接口的destroy方法: 如果Bean实现了DisposableBean接口,Spring容器在关闭时会调用destroy方法进行销毁。

  2. 使用@PreDestroy注解的方法: 如果Bean中有使用了@PreDestroy注解的方法,这些方法会在上述步骤完成后被调用。

总体顺序:

  1. 构造函数
  2. 属性注入
  3. InitializingBean的afterPropertiesSet方法
  4. @PostConstruct注解的方法

(Bean的使用阶段)

  1. @PreDestroy注解的方法
  2. DisposableBean的destroy方法

在这个生命周期过程中,Spring容器负责调用这些回调方法,确保Bean在初始化和销毁阶段都能够执行相应的逻辑。需要注意的是,具体情况可能会受到Bean的作用域、是否懒加载等因素的影响。

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

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

相关文章

听GPT 讲Rust源代码--compiler(4)

File: rust/compiler/rustc_codegen_gcc/src/back/mod.rs rust/compiler/rustc_codegen_gcc/src/back/mod.rs 文件是 Rust 编译器的源代码中的一个模块&#xff0c;主要负责与 GCC&#xff08;GNU 编译器集合&#xff09;相关的后端代码生成。 在 Rust 编译器的架构中&#xff…

视频倒放软件,看视频如何演绎“逆袭”之旅

你是否厌倦了日复一日的平淡生活&#xff0c;渴望时光倒流&#xff0c;重温那些逝去的精彩瞬间&#xff1f;在数字技术的世界里&#xff0c;这样的愿望或许不再遥不可及。视频倒放仿佛让时光倒流&#xff0c;给我们的视觉带来了全新的冲击&#xff0c;今天&#xff0c;让我们一…

vue3+Cesium 添加地面测控站台

效果 cesiumRadar.js import * as Cesium from cesium; export function addentities(viewer, res, index) {viewer.entities.add({id: index,position: Cesium.Cartesian3.fromDegrees(res[0], res[1]),wall: {positions: new Cesium.CallbackProperty(() > {return Cesiu…

Avalonia学习(十七)-CEF

今天开始继续Avalonia练习。 本节&#xff1a;CefNet 1.引入 CefNet.Avalonia.Eleven 2.项目引入 Program中加入 using Avalonia; using Avalonia.ReactiveUI; using Avalonia.Threading; using CefNet; using System; using System.IO; using System.Linq; using System…

边坡安全监测预警系统——高效率

安装边坡安全监测预警系统的原因是多方面的&#xff0c;涉及到社会效益、经济效益和环境效益。随着国家基础设施建设的快速发展&#xff0c;边坡安全监测预警系统的需求越来越迫切。 边坡安全监测预警系统对于保障人民生命财产安全具有重要意义。在山区、丘陵地带&#xff0c;边…

苹果Vision Pro将于1月27日上市!

在无数期待中&#xff0c;苹果全新产品Vision Pro头显终于定下上市日期。 彭博社记者马克古曼&#xff08;Mark Gurman&#xff09;于近日在X&#xff08;前推特&#xff09;平台爆料了这一信息&#xff0c;预计苹果Vision Pro头显将于2024年1月27日率先在美国上市。 在过去看…

【观察】Aginode安捷诺:坚守“长期主义”,服务中国数字经济

毫无疑问&#xff0c;随着整个社会加速数字化转型&#xff0c;尤其是5G、人工智能、大数据等技术兴起&#xff0c;以及智慧医疗、智慧金融、智能制造等应用加速落地&#xff0c;算力网络在经济社会发展中扮演了愈来愈重要的角色&#xff0c;成为支撑数字经济蓬勃发展的“新引擎…

移动神器RAX3000M路由器变身家庭云之四:开放LuCI管理界面,网站服务

前面已经改造成了家庭云供外网访问了。由于这个路由本来就是openwrt&#xff0c;openwrt本身的管理界面LuCI-admin很好用&#xff0c;但被屏蔽了&#xff0c;需要打开。 打开界面 ssh登录路由器&#xff0c;修改 /etc/config/uhttpd配置文件如下&#xff1a; config uhttpd …

深入浅出Prometheus架构原理

目录 1 Prometheus简介 2 Prometheus 的优势 2.1 Prometheus 适用于什么场景 2.2 Prometheus 不适合什么场景 3 Prometheus 的架构 4 Prometheus 的组件 4.1 组件介绍 4.1.1 Prometheus Server 4.1.2 Exporter 4.1.3 Push Gateway 4.1.4 Grafana 4.1.5 Alert…

elasticsearch的查询方式和数据库事务隔离级别的思考

项目中用到了 elasticsearch&#xff0c;发现有几种查询方式不太一样&#xff0c;思考了一下&#xff0c;总结如下 普通分页 等同于关系数据库的分页查询&#xff0c;例如 mysql 的 limit&#xff0c;如下 sql select * from test limit 100000,10 这种查询方式有一个问题&a…

PyQt 多线程多进程研究

杰哥&#xff0c;PyQT系统界面卡顿的问题是因为检测图片的耗时太长了&#xff0c;大概一张图片四十多秒。如果用多线程来解决耗时几秒的任务&#xff0c;是可以在之前卡顿问题上进一步解决的。但是不能解决像我们这种超长耗时的任务的&#xff0c;只能利用多线程来避免。我尝试…

计算机网络知识点

1. URI 和 URL 统一资源定位符&#xff08;Uniform Resource Locator&#xff0c;缩写&#xff1a;URL&#xff09;&#xff0c;是对资源的引用和访问该资源的方法。俗称网址&#xff0c;就是浏览器地址栏里面的内容。 URL 语法为&#xff1a;protocol://userInfohost:port/p…