Java面试宝典:说下Spring Bean的生命周期?

Java面试宝典专栏范围:JAVA基础,面向对象编程(OOP),异常处理,集合框架,Java I/O,多线程编程,设计模式,网络编程,框架和工具等全方位面试题详解
每日更新Java面试宝典专栏:Java面试宝典
感兴趣的可以先收藏起来,大家在遇到JAVA面试题等相关问题都可以给我留言咨询,希望帮助更多的人

封面图

回答重点

实例化: Spring 容器根据配置文件或注解实例化 Bean 对象。
属性注入: Spring 将依赖(通过构造器、setter 方法或字段注入)注入到 Bean 实例中。
初始化前的扩展机制: 若 Bean 实现了 BeanNameAware 等 aware 接口,则执行 aware 注入。
初始化前(BeanPostProcessor): 在 Bean 初始化之前,可通过 BeanPostProcessor 接口对 Bean 进行额外处理。
初始化: 调用 InitializingBean 接口的 afterPropertiesSet () 方法或通过 init - method 属性指定的初始化方法。
初始化后(BeanPostProcessor): 在 Bean 初始化后,可通过 BeanPostProcessor 进一步处理。
使用 Bean: Bean 初始化完成后,可被容器中的其他 Bean 使用。
销毁: 当容器关闭时,Spring 调用 DisposableBean 接口的 destroy () 方法或通过 destroy - method 属性指定的销毁方法。

实例化
属性注入
是否实现Aware接口
执行Aware注入
BeanPostProcessor前置处理
是否实现InitializingBean接口或有init - method
执行初始化方法
BeanPostProcessor后置处理
使用Bean
容器关闭
是否实现DisposableBean接口或有destroy - method
执行销毁方法
结束

详细解释

实例化

Spring 容器在启动过程中,会扫描指定的配置文件(如 XML 配置文件)或带有特定注解(如 @Component@Service@Repository@Controller 等)的类。对于 XML 配置,会根据 <bean> 标签的定义来创建 Bean 实例;对于注解方式,容器会利用反射机制来实例化对应的类。例如,当容器扫描到一个标注了 @Service 的类时,会创建该类的对象,这个对象就是一个 Bean 实例。

属性注入

  1. 构造器注入: 通过在目标类中定义带有参数的构造函数,Spring 会根据配置或注解找到对应的依赖对象,然后将这些依赖对象作为参数传递给构造函数来创建 Bean 实例。比如一个 UserService 类依赖 UserRepository,可以在 UserService 的构造函数中接收 UserRepository 作为参数,Spring 会自动将合适的 UserRepository 实例注入进来。
  2. setter 方法注入: 在目标类中为需要注入的属性提供对应的 setter 方法,Spring 会在 Bean 实例化之后,调用 setter 方法将依赖对象注入到属性中。例如,UserService 类有一个 userRepository 属性,提供 setUserRepository 方法,Spring 会调用该方法将 UserRepository 实例设置进去。
  3. 字段注入: 直接在类的字段上使用 @Autowired 等注解,Spring 会自动将匹配的依赖对象注入到该字段中。不过字段注入可能会导致一些测试和依赖管理上的问题,因为它使得依赖关系不够明确。

初始化前的扩展机制

当 Bean 实现了 BeanNameAware 接口时,Spring 容器会在 Bean 实例化之后,在其他初始化操作之前,将当前 Bean 在配置文件或注解中定义的名称注入到 Bean 中。通过实现该接口的 setBeanName 方法,Bean 可以获取自身的名称。类似的,还有 BeanFactoryAware 接口,实现它可以让 Bean 获取到当前的 BeanFactory 实例,从而可以在 Bean 内部对容器进行一些操作,比如获取其他 Bean 等。

初始化前(BeanPostProcessor)

BeanPostProcessor 是 Spring 提供的一个强大的扩展接口。开发者可以自定义实现该接口的类,在其中实现 postProcessBeforeInitialization 方法。当容器创建每个 Bean 实例并完成属性注入后,在调用 Bean 的初始化方法之前,会先调用所有注册的 BeanPostProcessorpostProcessBeforeInitialization 方法,开发者可以在这个方法中对 Bean 进行一些额外的处理,比如修改 Bean 的属性值、动态代理增强等操作。

初始化

  1. 实现 InitializingBean 接口: 当 Bean 实现了 InitializingBean 接口时,在 Bean 的属性注入完成之后,Spring 会调用该接口的 afterPropertiesSet方法。可以在这个方法中编写一些初始化逻辑,比如对一些资源的初始化操作、建立数据库连接等。
  2. 通过 init - method 属性: 在 XML 配置中,可以为 <bean> 标签指定 init - method 属性,其值为 Bean 类中定义的一个无参方法名。Spring 会在属性注入完成后,调用这个指定的方法进行初始化操作。同样,在使用注解配置时,也可以通过 @Bean 注解的 initMethod 属性来指定类似的初始化方法。

初始化后(BeanPostProcessor)

BeanPostProcessorpostProcessAfterInitialization 方法会在 Bean 的初始化方法调用完成之后被调用。在这里可以对已经初始化好的 Bean 进行进一步的处理,比如再次进行动态代理增强、添加一些额外的功能逻辑等。一些框架整合时,会利用这个时机来对 Bean 进行增强以实现特定的功能,比如 AOP 代理的创建等。

使用 Bean

当一个 Bean 完成了上述所有的生命周期步骤,就可以被容器中的其他 Bean 依赖和使用了。其他 Bean 可以通过属性注入等方式获取到这个 Bean 的实例,然后调用其提供的方法来完成业务逻辑。例如,OrderService 依赖 UserServiceUserService 已经完成初始化,OrderService 可以通过构造器注入获取到 UserService 实例,进而调用 UserService 中的方法来处理订单相关业务中涉及用户的操作。

销毁

  1. 实现 DisposableBean 接口: 当 Bean 实现了 DisposableBean 接口时,在 Spring 容器关闭时,会调用该接口的 destroy 方法。可以在这个方法中编写一些资源释放的逻辑,比如关闭数据库连接、释放文件句柄等。
  2. 通过 destroy - method 属性: 类似于初始化方法,在 XML 配置中可以为 <bean> 标签指定 destroy - method 属性,其值为 Bean 类中定义的一个无参方法名。Spring 容器关闭时,会调用这个指定的方法来进行资源清理等销毁操作。在注解配置中,也可以通过 @Bean 注解的 destroyMethod 属性来指定销毁方法。

Bean 的作用域(Scope)与生命周期的关系

Spring Bean 的生命周期还与其作用域密切相关:

  • Singleton(单例): 默认作用域,Bean 的生命周期与 Spring 容器的生命周期一致。在容器启动时创建,在容器关闭时销毁。
  • Prototype(原型): 每次请求时创建一个新的 Bean 实例,容器只负责创建,不管理其生命周期(不调用销毁方法)。
  • Request、Session、Application、WebSocket: 这些作用域用于 Web 应用中,Bean 的生命周期分别与 HTTP 请求、会话、应用或 WebSocket 的生命周期一致。

常见的生命周期场景有哪些?

数据库连接初始化与关闭

在一个 Web 应用中,经常需要与数据库进行交互。我们可以创建一个DatabaseConnection的 Bean。

  • 实例化与属性注入: Spring 容器启动时,根据配置实例化DatabaseConnection对象,并注入数据库连接所需的配置信息,比如数据库地址、用户名、密码等。
  • 初始化: 可以实现InitializingBean接口,在afterPropertiesSet方法中编写代码来建立实际的数据库连接,比如使用 JDBC 驱动来获取一个数据库连接对象。
  • 使用: 其他业务逻辑相关的 Bean,比如UserRepository,可以通过属性注入获取DatabaseConnection实例,然后利用这个连接来执行 SQL 语句,查询、插入、更新或删除数据。
  • 销毁: 当应用关闭时,实现DisposableBean接口,在destroy方法中关闭数据库连接,释放相关资源,避免资源泄漏。

日志记录器配置

很多应用都需要记录日志来跟踪程序运行情况。我们可以创建一个LoggerBean

  • 实例化与属性注入: Spring 容器启动时创建LoggerBean实例,并注入日志相关的配置,例如日志级别、日志文件路径等。
  • 初始化:LoggerBean中可以实现InitializingBean接口或者通过init - method指定一个初始化方法。在这个方法里,根据注入的配置信息来初始化日志记录器,比如设置日志输出格式,加载日志配置文件等。
  • 使用: 应用中的其他 Bean,比如OrderService,可以注入LoggerBean,在业务方法中调用LoggerBean的方法来记录日志,例如在处理订单时记录订单创建时间、订单状态变更等信息。
  • 销毁: 应用关闭时,LoggerBean的销毁方法(如果实现了DisposableBean接口或者配置了destroy - method)可以执行一些清理工作,比如关闭日志文件等。

消息队列生产者初始化

在分布式系统中,经常会使用消息队列来进行异步通信。假设有一个MessageProducer的 Bean 用于向消息队列发送消息。

  • 实例化与属性注入: Spring 容器启动时实例化MessageProducer,并注入消息队列的连接信息,如消息队列服务器地址、端口等,以及一些生产者相关的配置,比如消息持久化策略等。
  • 初始化: 可以通过实现InitializingBean接口,在afterPropertiesSet方法中建立与消息队列服务器的连接,创建消息生产者对象,并进行一些必要的配置初始化。
  • 使用: 业务 Bean,比如ProductService,当有新商品发布等事件发生时,可以注入MessageProducer,调用其方法将相关消息发送到消息队列中,以便其他系统或组件进行处理。
  • 销毁: 当应用关闭时,MessageProducer的销毁方法可以关闭与消息队列的连接,释放资源,确保系统正常退出。

在Spring中,如何自定义一个Bean的生命周期?

下面将通过多种方式来展示在 Spring 中自定义 Bean 生命周期的具体 Java 代码示例,包含使用接口、注解以及 XML 配置等方式。

1. 实现 InitializingBean 和 DisposableBean 接口

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanUsingInterfaces implements InitializingBean, DisposableBean {// 实现 InitializingBean 接口的 afterPropertiesSet 方法,用于初始化操作@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("MyBeanUsingInterfaces: Initializing...");}// 实现 DisposableBean 接口的 destroy 方法,用于销毁操作@Overridepublic void destroy() throws Exception {System.out.println("MyBeanUsingInterfaces: Destroying...");}
}

2. 使用 @PostConstruct 和 @PreDestroy 注解

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanUsingAnnotations {// 使用 @PostConstruct 注解,在 Bean 属性注入完成后执行初始化操作@PostConstructpublic void init() {System.out.println("MyBeanUsingAnnotations: Initializing...");}// 使用 @PreDestroy 注解,在 Spring 容器关闭时执行销毁操作@PreDestroypublic void destroy() {System.out.println("MyBeanUsingAnnotations: Destroying...");}
}

3. 在 XML 配置文件中指定 init-method 和 destroy-method 属性

首先创建一个 Java 类:

public class MyBeanUsingXml {// 初始化方法public void init() {System.out.println("MyBeanUsingXml: Initializing...");}// 销毁方法public void destroy() {System.out.println("MyBeanUsingXml: Destroying...");}
}

然后在 applicationContext.xml 中进行配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 定义 MyBeanUsingXml Bean,并指定初始化和销毁方法 --><bean id="myBeanUsingXml" class="com.example.MyBeanUsingXml"init-method="init" destroy-method="destroy"/>
</beans>

4. 实现 BeanPostProcessor 接口

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;// 使用 @Component 注解将该类注册为 Spring Bean
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {// 在 Bean 初始化前执行的方法@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println("Before Initialization: " + beanName);return bean;}// 在 Bean 初始化后执行的方法@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println("After Initialization: " + beanName);return bean;}
}

测试代码

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {// 对于使用注解的方式AnnotationConfigApplicationContext annotationContext = new AnnotationConfigApplicationContext();annotationContext.scan("com.example");annotationContext.refresh();// 获取并使用 BeanMyBeanUsingInterfaces myBeanUsingInterfaces = annotationContext.getBean(MyBeanUsingInterfaces.class);MyBeanUsingAnnotations myBeanUsingAnnotations = annotationContext.getBean(MyBeanUsingAnnotations.class);// 关闭容器,触发销毁方法annotationContext.close();// 对于使用 XML 配置的方式ClassPathXmlApplicationContext xmlContext = new ClassPathXmlApplicationContext("applicationContext.xml");MyBeanUsingXml myBeanUsingXml = xmlContext.getBean("myBeanUsingXml", MyBeanUsingXml.class);xmlContext.close();}
}

代码解释

  • 实现接口方式: 通过实现 InitializingBeanDisposableBean 接口,Spring 会自动调用相应的方法来完成初始化和销毁操作。
  • 注解方式: 使用 @PostConstruct@PreDestroy 注解,让代码更简洁,Spring 会在合适的时机调用被注解的方法。
  • XML 配置方式: 在 XML 中指定 init - methoddestroy - method,Spring 会根据配置调用对应的方法。
  • BeanPostProcessor 方式: 可以在所有 Bean 的初始化前后进行统一的处理,例如日志记录、属性修改等。

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

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

相关文章

web自动化-浏览器驱动下载

web-UI自动化最终要的一步就是下载安装浏览器驱动&#xff0c;下面是常用浏览器驱动的下载安装地址&#xff0c;以及安装之后如何验证的方法&#xff1a; 一、查看浏览器版本号 通过selenium进行自动化测试过程中&#xff0c;浏览器驱动的版本必须要和浏览器的版本保持一致&am…

PDF另存为图片的一个方法

说明 有时需要把PDF的每一页另存为图片。用Devexpress可以很方便的完成这个功能。 窗体上放置一个PdfViewer。 然后循环每一页 for (int i 1; i < pdfViewer1.PageCount; i) 调用 chg_pdf_to_bmp函数获得图片并保存 chg_pdf_to_bmp中调用了PdfViewer的CreateBitmap函数…

easyexcel快速使用

1.easyexcel EasyExcel是一个基于ava的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel 即通过java完成对excel的读写操作&#xff0c; 上传下载 2.easyexcel写操作 把java类中的对象写入到excel表格中 步骤 1.引入依赖 <depen…

opencv中minAreaRect函数输出角度问题

opencv中minAreaRect函数输出角度问题 新版opencv中minAreaRect函数计算最小外接矩形时&#xff0c;角度范围由旧版的[-90, 0]变为[0, 90]。 cv2.minAreaRect输入&#xff1a;四边形的四个点&#xff08;不要求顺序&#xff09;。 输出&#xff1a;最小外接矩形的中心点坐标x…

Python Pandas(7):Pandas 数据清洗

数据清洗是对一些没有用的数据进行处理的过程。很多数据集存在数据缺失、数据格式错误、错误数据或重复数据的情况&#xff0c;如果要使数据分析更加准确&#xff0c;就需要对这些没有用的数据进行处理。数据清洗与预处理的常见步骤&#xff1a; 缺失值处理&#xff1a;识别并…

UIView 与 CALayer 的联系和区别

今天说一下UIView 与 CALayer 一、UIView 和 CALayer 的关系 在 iOS 开发中&#xff0c;UIView 是用户界面的基础&#xff0c;它负责处理用户交互和绘制内容&#xff0c;而 CALayer 是 UIView 内部用于显示内容的核心图层&#xff08;Layer&#xff09;。每个 UIView 内部都有…

C++ Primer 函数基础

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

跟着李沐老师学习深度学习(十一)

经典的卷积神经网络 在本次笔记中主要介绍一些经典的卷积神经网络模型&#xff0c;主要包含以下&#xff1a; LeNet&#xff1a;最早发布的卷积神经网络之一&#xff0c;目的是识别图像中的手写数字&#xff1b;AlexNet&#xff1a; 是第一个在大规模视觉竞赛中击败传统计算机…

解锁电商数据宝藏:淘宝商品详情API实战指南

在电商蓬勃发展的今天&#xff0c;数据已成为驱动业务增长的核心引擎。对于商家、开发者以及数据分析师而言&#xff0c;获取精准、实时的商品数据至关重要。而淘宝&#xff0c;作为国内最大的电商平台&#xff0c;其海量商品数据更是蕴含着巨大的价值。 本文将带你深入探索淘…

网络安全 | 5G网络安全:未来无线通信的风险与对策

网络安全 | 5G网络安全&#xff1a;未来无线通信的风险与对策 一、前言二、5G 网络的技术特点2.1 超高速率与低延迟2.2 大容量连接与网络切片 三、5G 网络面临的安全风险3.1 网络架构安全风险3.2 设备终端安全风险3.3 应用场景安全风险3.4 用户隐私安全风险 四、5G 网络安全对策…

【OpenCV】入门教学

&#x1f3e0;大家好&#xff0c;我是Yui_&#x1f4ac; &#x1f351;如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x1f680;如有不懂&#xff0c;可以随时向我提问&#xff0c;我会全力讲解~ &#x1f52…

HCIA项目实践---ACL访问控制列表相关知识和配置过程

十 ACL访问控制列表 1 策略的概念 在网络连通之后&#xff0c; 把所有为了追求控制而实现的技术都叫策略 2 访问控制 在路由器流量流入或者流出的接口上&#xff0c;匹配流量&#xff0c;执行相应的动作。&#xff08;流量流入或者流出的接口并不是一个固定的概念而是一个相对的…

软考高级《系统架构设计师》知识点(二)

操作系统知识 操作系统概述 操作系统定义&#xff1a;能有效地组织和管理系统中的各种软/硬件资源&#xff0c;合理地组织计算机系统工作流程&#xff0c;控制程序的执行&#xff0c;并且向用户提供一个良好的工作环境和友好的接口。操作系统有三个重要的作用&#xff1a; 管理…

一口气入门前端——HTML5入门

HTML5 1.1 HTML 介绍 HTML&#xff08;超文本标记语言&#xff09;是一种用于 Web 开发的标记语言&#xff0c;主要用来格式化和显示网页内容。可以将其视为一种文本文件&#xff0c;浏览器能够读取该文本文件并显示其中的内容。HTML支持多种元素&#xff08;也称作标签&…

无人机信号调制技术原理

一、调制技术的必要性 频谱搬移&#xff1a;将低频的基带信号搬移到高频的载波上&#xff0c;便于天线辐射和传播。 信道复用&#xff1a; 利用不同的载波频率或调制方式&#xff0c;实现多路信号同时传输&#xff0c;提高信道利用率。 抗干扰&#xff1a; 通过选择合适的调…

MySql从入门到精通

第一部分 基础篇 1.概述 1.1 启动与停止MySql 启动 net start mysql80 停止 net stop mysql80 注意&#xff1a; mysql开机默认启动 1.2 客户端连接 方法一&#xff1a;使用MySQL提供的命令行客户端方法二&#xff1a;系统自带的命令行工具执行指令 mysql [-h 127.0.0.1] …

自己部署 DeepSeek 助力 Vue 开发:打造丝滑的时间线(Timeline )

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 自己…

基于Java SpringBoot以及vue前后端分离的旅游景区网站系统设计与实现

基于Java SpringBoot以及vue前后端分离的旅游景区网站系统设计与实现 本项目是一款基于Spring Boot和Vue.js开发的旅游景区管理系统&#xff0c;前端合后端的架构&#xff0c;支持用户在线浏览景区信息、预订门票&#xff0c;并提供完善的后台管理功能&#xff0c;包括订单管理…

HTML的入门

一、HTML HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是一种用来告知浏览器如何组织页面的标记语言。 超文本&#xff1a;就是超越了文本&#xff1b;HTML不仅仅可以用来显示文本(字符串、数字之类)&#xff0c;还可以显示视频、音频等…

【原创】springboot+vue考试考场座位安排管理系统设计与实现

个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交给天意。 研究背景&#xff1a; 随…