Spring——SpringBean初始接口

摘要

本文详细介绍了Spring框架中SpringBean的初始化接口和注解,包括BeanPostProcessor接口、InitializingBean接口和@PostConstruct注解。文章解释了这些接口和注解的原理、作用、适用场景,并提供了示例代码。最后,对比了不同SpringBean初始化方式的优缺点。

1. BeanPostProcessor接口

在 Spring 中,如果需要在 Spring 容器完成 bean 的属性设置之前 执行初始化逻辑,可以使用 BeanPostProcessor 接口中的 postProcessBeforeInitialization 方法。与 @PostConstructInitializingBean 不同,这种方式允许开发者在 属性填充完成之前 定制初始化逻辑。

1.1. BeanPostProcessor接口原理

Spring 提供了 BeanPostProcessor 接口,用于在 Spring 容器管理的 bean 初始化生命周期中加入自定义逻辑。它包含两个方法:

  1. postProcessBeforeInitialization
    • 在 bean 的初始化回调方法(如 @PostConstructafterPropertiesSet)之前执行。
    • 可用于拦截并修改 bean 的初始化前的逻辑。
  1. postProcessAfterInitialization
    • 在 bean 的初始化回调方法之后执行。
    • 通常用于代理增强等逻辑

1.2. BeanPostProcessor接口作用

  • postProcessBeforeInitialization 主要用于修改或验证 bean 的初始状态。
  • 设置默认值(如果属性未配置)。
  • 验证属性的正确性。
  • 添加初始化前的日志或调试信息。

1.3. BeanPostProcessor接口适用场景

  • 当你需要在依赖注入完成之前对 bean 进行拦截和自定义处理。
  • 需要跨多个 bean 应用统一的逻辑,比如:
    • 自动配置某些属性。
    • 统一校验所有 bean 的依赖关系。
  • 用于框架级功能(比如 AOP 或日志代理)。

1.4. BeanPostProcessor接口示例

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;@Component
public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof MyBean) {System.out.println("Before Initialization: " + beanName);MyBean myBean = (MyBean) bean;// 在属性填充之前,可以修改 bean 的初始状态if (myBean.getName() == null || myBean.getName().isEmpty()) {myBean.setName("DefaultName");}}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {if (bean instanceof MyBean) {System.out.println("After Initialization: " + beanName);}return bean;}
}
import org.springframework.stereotype.Component;@Component
public class MyBean {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void init() {System.out.println("Initializing MyBean with name: " + name);}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan(basePackages = "com.example")
public class MainApplication {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(MainApplication.class);MyBean myBean = context.getBean(MyBean.class);System.out.println("Bean name after processing: " + myBean.getName());}
}
Before Initialization: myBean
Initializing MyBean with name: DefaultName
After Initialization: myBean
Bean name after processing: DefaultName

2. InitializingBean接口

InitializingBean接口是Spring框架中的一个生命周期接口,用于在Spring容器完成bean的属性设置后执行初始化逻辑。实现了该接口的bean会在Spring容器注入完所有的依赖之后自动调用afterPropertiesSet方法,从而让开发者在bean初始化后执行一些额外的操作,如检查配置、初始化数据等。

2.1. InitializingBean接口原理

实现InitializingBean接口Spring对象执行顺序

  1. Spring容器创建bean:当Spring容器启动时,会根据配置文件(XML或者注解)扫描到所有的bean,并创建它们。
  2. 依赖注入:Spring会将配置文件中定义的属性注入到bean实例中。这些属性可以是基础类型、引用类型或集合类型等。
  3. 调用afterPropertiesSet方法:如果bean实现了InitializingBean接口,Spring会在所有依赖注入完成后自动调用该bean的afterPropertiesSet方法。这是Spring容器在bean初始化的过程中执行的一部分。

2.2. InitializingBean接口适用场景

afterPropertiesSet方法通常用于执行初始化任务,比如:

  • 校验配置参数是否正确。
  • 初始化一些资源或数据。
  • 打印调试信息,确认bean已经成功初始化。

2.3. InitializingBean接口示例

假设你有一个类需要在Spring容器初始化完成后执行一些初始化工作,可以通过实现InitializingBean接口来实现。

import org.springframework.beans.factory.InitializingBean;public class MyBean implements InitializingBean {private String name;// Spring容器会通过依赖注入注入name属性public void setName(String name) {this.name = name;}// 实现 afterPropertiesSet 方法,完成初始化工作@Overridepublic void afterPropertiesSet() throws Exception {// 初始化逻辑,比如验证name属性是否为空if (name == null || name.isEmpty()) {throw new IllegalArgumentException("Name property must be set");}System.out.println("MyBean initialized with name: " + name);}
}

在Spring配置文件中,您可以像下面这样定义该bean:

<bean id="myBean" class="com.example.MyBean"><property name="name" value="SpringBeanExample" />
</bean>

使用注解配置:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class MyBean implements InitializingBean {@Value("${bean.name}")private String name;@Overridepublic void afterPropertiesSet() throws Exception {if (name == null || name.isEmpty()) {throw new IllegalArgumentException("Name property must be set");}System.out.println("MyBean initialized with name: " + name);}
}

2.4. InitializingBean接口注意事项

  • InitializingBean接口的afterPropertiesSet方法可以与自定义的初始化方法一起使用。Spring也允许在bean的配置中指定一个init-method属性,用于指定一个自定义的初始化方法。如果bean同时实现了InitializingBean接口并配置了init-method,则会按顺序执行。
  • Spring的@PostConstruct注解提供了一种更简洁的方式来实现初始化逻辑,可以在方法上直接添加该注解,Spring会在bean初始化后自动调用它。
import org.springframework.stereotype.Component;import jakarta.annotation.PostConstruct;@Component
public class MyBean {private String name;// Setter 方法,Spring 容器会通过依赖注入设置属性public void setName(String name) {this.name = name;}// 使用 @PostConstruct 标记初始化方法@PostConstructpublic void init() {if (name == null || name.isEmpty()) {throw new IllegalArgumentException("Name property must be set");}System.out.println("MyBean initialized with name: " + name);}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic MyBean myBean() {MyBean myBean = new MyBean();myBean.setName("SpringExample");return myBean;}
}
  • 如果使用的是 Java 9 或更高版本,需要引入 jakarta.annotation 的依赖:
<dependency><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>2.1.1</version>
</dependency>
  • @PostConstruct 方法要求:
  • 方法无返回值 (void)。
  • 方法不能接受参数。
  • 方法不能是 static 的。

3. @PostConstruct注解

在 Spring 中,@PostConstruct 是 Java 标准中的注解,位于 jakarta.annotation(或早期的 javax.annotation)包中。Spring 对该注解提供了支持,用于在 bean 完成依赖注入后 自动调用标注的方法,执行初始化逻辑。它是由 Spring 的 BeanPostProcessor 实现机制来完成的。

3.1. @PostConstruct注解原理

具体原理流程如下:

  1. Bean 实例化:Spring 容器扫描到配置的类并创建该类的实例。
  2. 依赖注入:容器根据配置将需要的依赖注入到该实例中。
  3. 调用 @PostConstruct 方法
    • Spring 容器会检测到 bean 中是否有被 @PostConstruct 标注的方法。
    • 如果存在,该方法会在依赖注入完成后、初始化逻辑执行前被调用。

这个功能是通过 Spring 内部的 CommonAnnotationBeanPostProcessor 实现的,该类实现了 Spring 的 BeanPostProcessor 接口,并负责处理 @PostConstruct 和其他类似注解(如 @PreDestroy)。

3.2. @PostConstruct注解作用

  1. BeanPostProcessor: Spring 使用 CommonAnnotationBeanPostProcessor,它是 BeanPostProcessor 的一个实现类。
    在 bean 初始化阶段,它会调用每个 bean 的 postProcessBeforeInitialization 方法,检查是否有 @PostConstruct 标注的方法。
  2. 调用 @PostConstruct 方法
    • 找到标注的方法。
    • 利用反射调用该方法。
    • 确保该方法只执行一次。

3.3. @PostConstruct注解示例

import jakarta.annotation.PostConstruct;
import org.springframework.stereotype.Component;@Component
public class MyBean {private String name;public void setName(String name) {this.name = name;}// @PostConstruct 用于初始化逻辑@PostConstructpublic void init() {if (name == null || name.isEmpty()) {this.name = "DefaultName";  // 如果未设置值,赋予默认值}System.out.println("MyBean initialized with name: " + name);}
}

配置类示例

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AppConfig {@Beanpublic MyBean myBean() {MyBean myBean = new MyBean();myBean.setName("SpringExample");return myBean;}
}

运行测试类

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class MainApplication {public static void main(String[] args) {ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);MyBean myBean = context.getBean(MyBean.class);System.out.println("Bean is fully initialized and ready to use.");}
}

4. SpringBean初始化方式的对比

方式

定义位置

灵活性

优缺点

@PostConstruct

方法上,注解方式

简单且通用

优势:标准注解,语义清晰,易用。缺点:Java 9+ 需额外引入依赖。

InitializingBean

实现 InitializingBean

接口

中等

优势:Spring 原生支持。缺点:需要绑定到 Spring 接口,不灵活。

XML init-method

XML 配置文件中定义初始化方法

灵活

优势:无需修改代码。缺点:XML 配置繁琐,不够直观。

Java Config 方法

Java 配置类中直接调用初始化逻辑

灵活性高

优势:可自定义。缺点:需要在配置类中管理所有初始化逻辑。

方法

调用时机

用途

优点

postProcessBeforeInitialization

Bean 属性填充前

属性填充前拦截并修改 bean

灵活,适合跨 bean 的通用逻辑处理

@PostConstruct

属性填充完成后,初始化方法之前

依赖注入完成后的初始化逻辑

简洁,适合单个 bean 的初始化工作

afterPropertiesSet

属性填充完成后,@PostConstruct

之后

初始化任务

Spring 专用接口,适合复杂初始化

博文参考

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

「嵌入式系统设计与实现」书评:学习一个STM32的案例

本文最早发表于电子发烧友论坛&#xff1a;【新提醒】【「嵌入式系统设计与实现」阅读体验】 学习一个STM32的案例 - 发烧友官方/活动 - 电子技术论坛 - 广受欢迎的专业电子论坛!https://bbs.elecfans.com/jishu_2467617_1_1.html 感谢电子发烧友论坛和电子工业出版社的赠书。 …

操作系统——大容量存储结构

笔记内容及图片整理自XJTUSE “操作系统” 课程ppt&#xff0c;仅供学习交流使用&#xff0c;谢谢。 大容量存储结构概述 磁盘 磁盘为现代计算机系统提供大量外存。每个盘片为平的圆状&#xff08;类似CD&#xff09;&#xff0c;普通盘片直径为4.5~9.0厘米。盘片的两面都涂着…

Redis从入门到进阶(总结)

以下内容均以CentOS7为背景。 一、Redis安装及启动 mysql&#xff08;读&#xff1a;2000/s&#xff1b;写&#xff1a;600/s&#xff09; redis&#xff08;读&#xff1a;10w/s&#xff1b;写&#xff1a;8w/s&#xff09;通过官方给出的数据单机并发可以达到10w/s&#xf…

Java进阶(注解,设计模式,对象克隆)

Java进阶(注解&#xff0c;设计模式&#xff0c;对象克隆) 一. 注解 1.1 什么是注解 java中注解(Annotation)&#xff0c;又称java标注&#xff0c;是一种特殊的注释 可以添加在包&#xff0c;类&#xff0c;成员变量&#xff0c;方法&#xff0c;参数等内容上 注解会随同…

使用 Gin 框架构建 RESTful 博客 API

使用 Gin 框架构建 RESTful 博客 API 引言 在现代 Web 开发中&#xff0c;RESTful API 是一种非常流行的设计风格&#xff0c;它通过 HTTP 协议与客户端进行通信&#xff0c;提供了灵活且易于扩展的接口。Go 语言以其高效的并发处理能力和简洁的语法&#xff0c;成为了构建高…

Leecode刷题C语言之骑士在棋盘上的概率

执行结果:通过 执行用时和内存消耗如下&#xff1a; 代码如下&#xff1a; static int dirs[8][2] {{-2, -1}, {-2, 1}, {2, -1}, {2, 1}, {-1, -2}, {-1, 2}, {1, -2}, {1, 2}};double knightProbability(int n, int k, int row, int column){double dp[200][30][30];mem…

21. C++STL 7(8000字详解list及其迭代器的模拟实现)

⭐本篇重点&#xff1a;STL中的list及其迭代器的模拟实现和测试 ⭐本篇代码&#xff1a;c学习 橘子真甜/c-learning-of-yzc - 码云 - 开源中国 (gitee.com) 目录 一. list的节点 二. list的迭代器 2.1 迭代器框架 2.2 迭代器实现 三. list的实现 3.1 list的构造函数 3.…

Docker打包SpringBoot项目

一、项目打成jar包 在进行docker打包之前&#xff0c;先确定一下&#xff0c;项目能够正常的打成JAR包&#xff0c;并且启动之后能够正常的访问。这一步看似是可有可无&#xff0c;但是能避免后期的一些无厘头问题。 二、Dockerfile 项目打包成功之后&#xff0c;需要编写Doc…

零基础学鸿蒙开发--第九篇--网络请求

12. ⽹络请求 鸿蒙系统提供了 http 模块 ⽤于发送 http 请求&#xff0c;另外&#xff0c; OpenHarmony社区基于该模块将前端开发中常⽤的⽹络请 求库 axios 移植到了鸿蒙系统&#xff0c;因此我们也可以在鸿蒙系统中使⽤ axios 发送 http 请求&#xff0c;下⾯重点为⼤家介绍…

133.WEB渗透测试-信息收集-小程序、app(4)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;132.WEB渗透测试-信息收集-小程序、app&#xff08;3&#xff09; 输入命令&#xff1a;…

Pointnet++改进71:添加LFE模块|高效长距离注意力网络

简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入LFE模块,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三 1.理…

Android仿美团左右联动购物列表

Android仿美团左右联动购物列表 左右联动购物列表&#xff0c;不难。 一、思路&#xff1a; 两个RecycleView 二、效果图&#xff1a; 三、关键代码&#xff1a; public class MainActivity extends AppCompatActivity {private RecyclerView rl_left;private RecyclerVie…

Mitel MiCollab 企业协作平台 任意文件读取漏洞复现(CVE-2024-41713)

0x01 产品简介 Mitel MiCollab是加拿大Mitel(敏迪)公司推出的一款企业级协作平台,旨在为企业提供统一、高效、安全的通信与协作解决方案。通过该平台,员工可以在任何时间、任何地点,使用任何设备,实现即时通信、语音通话、视频会议、文件共享等功能,从而提升工作效率和…

深度学习camp-第J3-1周:DenseNet算法 实现乳腺癌识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 我的环境 语言环境&#xff1a;Python 3.12编译器&#xff1a;Jupyter Lab深度学习环境&#xff1a;Pytorch 2.4.1 Torchvision 0.19.1数据集&#xff1a;乳腺…

Elasticsearch 单节点安全配置与用户认证

Elasticsearch 单节点安全配置与用户认证 安全扫描时发现了一个高危漏洞&#xff1a;Elasticsearch 未授权访问 。在使用 Elasticsearch 构建搜索引擎或处理大规模数据时&#xff0c;需要启用基本的安全功能来防止未经授权的访问。本文将通过简单的配置步骤&#xff0c;为单节…

Vulhub:Shiro[漏洞复现]

目录 CVE-2010-3863(Shiro未授权) 使用浏览器访问靶场主页面 使用Yakit进行抓包 使用ffuf对靶机8080端口进行根路径FUZZ CVE-2016-4437(Shiro-550) 使用浏览器访问靶场主页面 使用Yakit进行抓包 使用Yakit反连中自带的Yso-Java Hack进行漏洞利用 首先运行脚本生成一个…

数学拯救世界(一)———寻“数”记

一、 很久很久以前&#xff0c;在一个只认识整数和小数的国度&#xff0c;有一个很残暴的国王提了一个要求&#xff1a;要是不能表示出把一段1米的绳子三等分后的大小&#xff0c;就要把所有的大臣杀掉。 1➗3 0.333&#xff0c;怎么办呀&#xff1f;怎么办呀&#xff1f; 袁q…

Codeforces Round 991 (Div. 3)题解

先随随便便写一点东西吧&#xff0c;毕竟只是一场div3 A. Line Breaks 思路&#xff1a;一道很简单的模拟题吧&#xff0c;就是遍历一遍&#xff0c;当大于x的时候就break&#xff0c;然后前面那个就是找到的前x个字的总长度不超过m #include<bits/stdc.h> using names…

掌握谈判技巧,达成双赢协议

在当今竞争激烈且合作频繁的社会环境中&#xff0c;谈判成为了我们解决分歧、谋求共同发展的重要手段。无论是商业合作、职场交流&#xff0c;还是国际事务协商&#xff0c;掌握谈判技巧以达成双赢协议都具有极其关键的意义。它不仅能够让各方在利益分配上找到平衡点&#xff0…

基于Matlab特征提取与浅层神经网络的数字图像处理乳腺癌检测系统(GUI界面+训练代码+数据集)

本研究提出了一种结合数字图像处理技术、特征提取与浅层神经网络的创新癌症检测系统&#xff0c;旨在为医学图像的分析和早期癌症检测提供有效支持。系统主要处理癌症与正常组织的医学图像&#xff0c;通过灰度共生矩阵&#xff08;GLCM&#xff09;等方法&#xff0c;从图像中…