【Spring高级】Aware与InitializingBean接口
目录
- Aware接口
- 概述
- 为什么需要Aware接口
- InitializingBean接口
- @Autoware失效分析
Aware接口
概述
在Spring框架中,Aware 接口是一种常用的设计模式,用于允许bean在初始化时感知(或获取)Spring容器中的某些资源或环境信息。这些接口通常以 ...Aware 结尾,并且Spring提供了许多这样的接口。以下是一些常见的 Aware 接口及其用途:
BeanNameAware:- 允许bean获取其在Spring容器中的名称。
- 实现此接口的bean可以通过
setBeanName(String name)方法设置其名称。
BeanFactoryAware:- 允许bean获取对其创建它的
BeanFactory的引用。 - 实现此接口的bean可以通过
setBeanFactory(BeanFactory beanFactory)方法设置其BeanFactory。
- 允许bean获取对其创建它的
ApplicationContextAware:- 允许bean获取对其运行时的
ApplicationContext的引用。 - 实现此接口的bean可以通过
setApplicationContext(ApplicationContext applicationContext)方法设置其ApplicationContext。
- 允许bean获取对其运行时的
ResourceLoaderAware:- 允许bean获取
ResourceLoader,它可以用来加载类路径上的资源。 - 实现此接口的bean可以通过
setResourceLoader(ResourceLoader resourceLoader)方法设置其ResourceLoader。
- 允许bean获取
MessageSourceAware:- 允许bean获取
MessageSource,它用于国际化消息解析。 - 实现此接口的bean可以通过
setMessageSource(MessageSource messageSource)方法设置其MessageSource。
- 允许bean获取
ApplicationEventPublisherAware:- 允许bean获取
ApplicationEventPublisher,它用于发布应用事件。 - 实现此接口的bean可以通过
setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)方法设置其ApplicationEventPublisher。
- 允许bean获取
EnvironmentAware:- 允许bean获取
Environment,它提供了对应用程序运行时的环境属性的访问。 - 实现此接口的bean可以通过
setEnvironment(Environment environment)方法设置其Environment。
- 允许bean获取
使用这些 Aware 接口,Spring bean可以在其生命周期的早期阶段获取到所需的资源或服务,然后利用这些资源或服务执行其逻辑。例如,ApplicationContextAware 允许一个bean访问整个应用上下文,这可能对于查找其他bean或资源非常有用。
要实现这些接口,你只需要在你的bean类中添加相应的 set 方法,并在Spring配置中声明这个bean。Spring容器会自动调用这些 set 方法,并传递相应的资源或服务。
例如,要实现 ApplicationContextAware,你可以这样做:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; @Component
public class MyBean implements ApplicationContextAware { private ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } public ApplicationContext getApplicationContext() { return applicationContext; }
}
在这个例子中,MyBean 实现了 ApplicationContextAware 接口,并通过 setApplicationContext 方法获取了 ApplicationContext 的引用。然后,这个bean就可以使用 applicationContext 属性来访问Spring容器中的其他bean或服务了。
为什么需要Aware接口
有了@Autoware注解,为什么还需要 Aware 接口?
- 因为
Aware接口提供了一种机制,让bean能够在Spring容器初始化它们的过程中获取到额外的信息或资源,这些信息或资源可能无法通过简单的依赖注入来获取。 - @Autowired 的解析需要用到 bean 后处理器, 属于扩展功能, 而 Aware 接口属于内置功能, 不加任何扩展, Spring 就能识别。某些情况下, 扩展功能会失效, 而内置功能不会失效。
Aware接口提供了一种更灵活的方式来获取资源,因为它们可以在bean的初始化过程中任何时候被调用。相比之下,依赖注入通常发生在bean创建的过程中,并且受到Spring容器管理的依赖关系的限制。- 虽然可以通过
@Autowired直接注入ApplicationContext,但这可能会增加代码的耦合度,因为任何需要访问ApplicationContext的类都必须依赖它。使用ApplicationContextAware接口可以让这种依赖更加显式,并且可以通过实现接口来控制哪些类实际上需要这种依赖。
InitializingBean接口
InitializingBean接口是Spring框架中的一个回调接口,它定义了一个afterPropertiesSet()方法。这允许bean在依赖注入完成后执行一些初始化逻辑。当一个bean的所有属性都被Spring容器通过依赖注入设置完毕之后,afterPropertiesSet()方法会被自动调用。
实现InitializingBean接口的bean可以在afterPropertiesSet()方法中编写自定义的初始化代码。通常用于执行一些在依赖注入后必须执行的设置或准备操作。这使得bean可以在其属性被设置之后执行一些初始化逻辑。
下面是一个实现InitializingBean接口的简单例子:
import org.springframework.beans.factory.InitializingBean; public class MyBean implements InitializingBean { private String someProperty; public void setSomeProperty(String someProperty) { this.someProperty = someProperty; } @Override public void afterPropertiesSet() throws Exception { // 初始化逻辑,这将在所有属性被设置之后执行 System.out.println("Properties have been set on the bean. Initializing..."); // 例如,可以在这里进行资源加载、数据初始化等操作 } public void doSomething() { // 业务逻辑 }
}
在这个例子中,MyBean 类实现了 InitializingBean 接口,并覆盖了 afterPropertiesSet() 方法。当 Spring 容器创建 MyBean 的实例并设置其所有属性之后,它会调用 afterPropertiesSet() 方法。
虽然InitializingBean接口提供了一种通用的初始化机制,但Spring也支持使用@PostConstruct注解作为替代。
InitializingBean接口的使用不是强制性的。Spring也允许通过在XML配置文件中使用<bean>元素的init-method属性,或者在注解配置中使用@PostConstruct注解来指定初始化方法。@PostConstruct注解的方法会在依赖注入完成后自动被调用,这与afterPropertiesSet()方法的效果相同,但它是Java EE提供的替代InitializingBean接口的方式来执行初始化逻辑。
此外,你还可以通过实现DisposableBean接口并提供destroy()方法的实现来定义bean销毁时的逻辑。当bean不再需要并被Spring容器销毁时,destroy()方法会被自动调用。这类似于InitializingBean接口,但用于bean生命周期的结束阶段。
@Autoware失效分析
看下面一个例子:
配置类
package com.cys.demo02.Chapter06;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;@Configuration
public class MyConfig {private static final Logger log = LoggerFactory.getLogger(MyConfig.class);@Autowiredpublic void setApplicationContext(ApplicationContext applicationContext) {log.debug("注入 ApplicationContext");}@PostConstructpublic void init() {log.debug("初始化");}}
测试类
package com.cys.demo02.Chapter06;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.context.support.GenericApplicationContext;public class TestAutowiredInvalidated {private static final Logger log = LoggerFactory.getLogger(TestAutowiredInvalidated.class);public static void main(String[] args) {GenericApplicationContext context = new GenericApplicationContext();context.registerBean("myConfig1", MyConfig.class);context.registerBean(AutowiredAnnotationBeanPostProcessor.class);context.registerBean(CommonAnnotationBeanPostProcessor.class);context.registerBean(ConfigurationClassPostProcessor.class);context.refresh();context.close();}
}
运行后可以正常打印出依赖注入时打印的信息:
12:43:34.799 [main] DEBUG com.cys.demo02.Chapter06.MyConfig - 注入 ApplicationContext
12:43:34.800 [main] DEBUG com.cys.demo02.Chapter06.MyConfig - 初始化
但是当我们给配置类增加一个BeanFactoryPostProcessor,如下:
package com.cys.demo02.Chapter06;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import javax.annotation.PostConstruct;@Configuration
public class MyConfig {private static final Logger log = LoggerFactory.getLogger(MyConfig.class);@Autowiredpublic void setApplicationContext(ApplicationContext applicationContext) {log.debug("注入 ApplicationContext");}@PostConstructpublic void init() {log.debug("初始化");}@Bean //添加一个beanFactory的后处理器public BeanFactoryPostProcessor processor1(){return configurableListableBeanFactory -> {log.debug("执行processor1");};}}
运行后发现,未打印出依赖注入时打印的信息。这是为什么呢?
Java 配置类不包含 BeanFactoryPostProcessor 的情况
Java 配置类包含 BeanFactoryPostProcessor 的情况,因为要创建其中的 BeanFactoryPostProcessor 必须提前创建 Java 配置类,而此时的 BeanPostProcessor 还未准备好,导致 @Autowired 等注解失效
对应代码
@Configuration
public class MyConfig1 {private static final Logger log = LoggerFactory.getLogger(MyConfig1.class);@Autowiredpublic void setApplicationContext(ApplicationContext applicationContext) {log.debug("注入 ApplicationContext");}@PostConstructpublic void init() {log.debug("初始化");}@Bean // 注释或添加 beanFactory 后处理器对应上方两种情况public BeanFactoryPostProcessor processor1() {return beanFactory -> {log.debug("执行 processor1");};}}
解决方法:
- 用内置依赖注入和初始化取代扩展依赖注入和初始化,也就是我们前面说的
Aware接口 - 用静态工厂方法代替实例工厂方法,避免工厂对象提前被创建
相关文章:
【Spring高级】Aware与InitializingBean接口
目录 Aware接口概述为什么需要Aware接口 InitializingBean接口Autoware失效分析 Aware接口 概述 在Spring框架中,Aware 接口是一种常用的设计模式,用于允许bean在初始化时感知(或获取)Spring容器中的某些资源或环境信息。这些接…...
打造你的HTML5打地鼠游戏:零基础入门教程
🌟 前言 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…...
C++默认构造函数/拷贝构造函数/赋值构造函数
概述 本文主要讲解C默认构造函数,拷贝构造函数和赋值构造函数在哪些场景下会被调用到 代码 类定义 class A{public:A() { cout<<"construct function"<<endl; }A(const A& other) { cout<<"copy construct function"…...
前端框架的发展历史介绍
前端框架的发展历史是Web技术进步的一个重要方面。从最初的简单HTML页面到现在的复杂单页应用程序(SPA),前端框架和库的发展极大地推动了Web应用程序的构建方式。以下是一些关键的前端框架和库,以及它们的发布年份、创建者和主要特…...
Linux 基本命令
文章目录 1.echo2.cd3.find4.mkdir5.cp6.rm7.wc8.tar9.tail10.vim11.grep12.sed13 touch14 ls15 快捷键16 ln17 mv18 useradd19 usermod20 su 每天一个Linux命令 提示:以下是本篇文章正文内容,下面案例可供参考 1.echo 中文 (Chinese): “回声” 或 “输…...
怎么查看电脑是不是固态硬盘?简单几个步骤判断
随着科技的发展,固态硬盘(Solid State Drive,简称SSD)已成为现代电脑的标配。相较于传统的机械硬盘,固态硬盘在读写速度、稳定性和耐用性等方面都有显著优势。但是,对于不熟悉电脑硬件的用户来说࿰…...
在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!
写在开头 经过上几篇博文的学习,我们知道在Java中可以通过new Thread().start()创建一个线程,那今天我们就来思考另外一个问题:线程的终止 自然终止有两种情况: 1. 线程的任务执行完成; 2. 线程在执行任务过程中发生异…...
指数函数与三角函数乘积的积分公式
先上公式,公式正确,用欧拉公式即可证明。 数学公式不好打字,我就发截图。 欧拉公式证明如下:...
代码随想录算法训练营第五九天 | 下一个更大元素II、接雨水
目录 下一个更大元素II接雨水 LeetCode 503.下一个更大元素II LeetCode 42. 接雨水 下一个更大元素II 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。 数字 x 的 下一…...
LeetCode(力扣)算法题_2864_最大二进制奇数
最大二进制奇数 题目描述 给你一个 二进制 字符串 s ,其中至少包含一个 1 。 你必须按某种方式 重新排列 字符串中的位,使得到的二进制数字是可以由该组合生成的 最大二进制奇数 。 以字符串形式,表示并返回可以由给定组合生成的最大二进…...
食药物质创新 赋能中式滋补健康产业发展交流会圆满结束
3月5日,“食药物质创新 赋能中式滋补健康产业发展交流会”在山东国际会展中心召开。本次会议由中国生物发酵产业协会主办,浙江科技大学、未名太研生物科技(绍兴)有限公司承办,汇乐达供应链服务(常州)有限责任公司支持。本次论坛旨在加强行业创…...
用好大模型、承载“头雁领航”使命,央企如何三路出击?
作者 | 曾响铃 文 | 响铃说 智能化成为两会热议话题,2024政府工作报告中也直接提到要深化大数据、人工智能等研发应用,开展“人工智能”行动。 毫无疑问,大模型热潮下,以智能化推进传统产业升级已经成为普遍共识。 具体如何做…...
LabVIEW飞机液压基础试验台测试系统
LabVIEW飞机液压基础试验台测试系统 为解决飞机液压基础实验台人工控制操作复杂、测试时间长、测试流程易出错等问题,开发了一套基于LabVIEW的飞机液压基础试验台测试系统。该系统通过计算机控制,实现了高度自动化的测试流程,有效提高了测试…...
STM32第十课:串口发送
一、usart串口 1.1 USART串口协议 串口通讯(Serial Communication) 是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,电子工程师在调试设备时也经常使用该通讯方式输出调试信息。在计算机科学里&…...
淘宝扭蛋机小程序:探索未知的惊喜之旅
你是否曾在商场里被那闪闪发光的扭蛋机吸引,却因为种种原因无法下手?现在,淘宝扭蛋机小程序带给你全新的扭蛋体验,让你随时随地都能感受到那份未知的惊喜。 淘宝扭蛋机小程序是一款集娱乐与购物于一体的全新应用。它汇聚了众多热…...
[nlp入门论文精读] | Transformer
写在前面 最近工作从CV转向了NLP,于是空余时间便跟着哔哩哔哩李沐老师的视频学习。其实研一NLP课程讲论文的时候,我们小组就选择了经典的Attention和Bert,但还有很多细节并不完全理解,实际使用时也很困惑。 因此这个系列就来记…...
科技回顾,飞凌嵌入式受邀亮相第八届瑞芯微开发者大会「RKDC2024」
2024年3月7日~8日,第八届瑞芯微开发者大会(RKDC2024)在福州举行,本届大会以“AI芯片AI应用AloT”为主题,邀请各行业的开发者共启数智化未来。 本届大会亮点颇多,不仅有13大芯片应用展示、9场产品和技术论坛…...
代码随想录算法训练营第五十九天丨503. 下一个更大元素 II、42. 接雨水
503. 下一个更大元素 II 还是比较容易想的,扩展数组一倍即可。 class Solution:def nextGreaterElements(self, nums: List[int]) -> List[int]:extended_nums nums * 2n len(nums)mono []res [- 1] * nfor i, num in enumerate(extended_nums):while mono…...
全代码分享|R语言孟德尔随机化怎么做?TwoSampleMR包MR一套标准流程
文章目录 1.前言1.1 成立条件1.2 三大要素1.3 统计原理 2.demo2.1 加载R包2.2 主要MR分析2.3 MR补充分析、多态性、验证 2.4 结果可视化 1.前言 孟德尔随机化(Mendelian randomization,MR)是一种利用基因变异作为工具变量来评估暴露与结果之间因果关系的统计方法。…...
【AI视野·今日NLP 自然语言处理论文速览 第八十四期】Thu, 7 Mar 2024
AI视野今日CS.NLP 自然语言处理论文速览 Thu, 7 Mar 2024 Totally 52 papers 👉上期速览✈更多精彩请移步主页 Daily Computation and Language Papers The Heuristic Core: Understanding Subnetwork Generalization in Pretrained Language Models Authors Adith…...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
MySQL账号权限管理指南:安全创建账户与精细授权技巧
在MySQL数据库管理中,合理创建用户账号并分配精确权限是保障数据安全的核心环节。直接使用root账号进行所有操作不仅危险且难以审计操作行为。今天我们来全面解析MySQL账号创建与权限分配的专业方法。 一、为何需要创建独立账号? 最小权限原则…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...
