Spring揭秘:Aware接口应用场景及实现原理!
内容概要
Aware
接口赋予了Bean更多自感知的能力,通过实现不同的Aware
接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContext
、BeanFactory
等。
这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性,从而让Spring的IoC容器变得更加强大和灵活。
核心概念
它能解决什么问题?
在Spring中,Aware
接口是一种标记接口,它本身并没有定义任何方法,但是Spring提供了一系列以Aware
命名的接口,如BeanNameAware
、BeanFactoryAware
、ApplicationContextAware
等。
这些接口定义了一些回调方法,通过这些回调方法,Spring容器在初始化Bean时会将容器中的一些资源、状态、环境信息注入到Bean中,使Bean能够感知到这些信息并据此进行相应的操作。
Aware
接口主要用来解决以下技术问题:
- 依赖注入:Spring的核心功能之一就是依赖注入(DI),但有时候标准的依赖注入方式可能无法满足某些特定的需求。例如,当需要访问当前Bean的名称、BeanFactory或ApplicationContext等信息,通过实现相应的
Aware
接口,可以让Spring容器在初始化Bean时自动将这些信息注入到Bean中。 - 环境感知:有时候,Bean的行为可能需要根据其所处的环境进行调整,例如,在不同的ApplicationContext中,Bean可能需要进行不同的配置或初始化操作,通过实现
ApplicationContextAware
接口,Bean可以访问到当前的ApplicationContext,并据此进行环境感知的操作。 - 资源访问:除了基本的依赖注入和环境感知外,
Aware
接口还可以用于访问Spring容器中的其他资源。例如,通过实现ResourceLoaderAware
接口,Bean可以获得一个ResourceLoader
的引用,用于加载类路径下的资源文件。
它有哪些子类拓展?
以下是Aware
接口的一些常见的子类实现,如下:
- BeanNameAware: 实现此接口的bean可以获得其在Spring容器中的名称,当bean被创建并添加到容器中时,Spring会调用
setBeanName(String name)
方法。 - BeanFactoryAware: 实现此接口的bean可以获得对其所在的
BeanFactory
的引用,这允许bean直接访问容器以查找或操作其他bean,通过setBeanFactory(BeanFactory beanFactory)
方法注入。 - ApplicationContextAware: 与
BeanFactoryAware
类似,但是提供对更高级的ApplicationContext
的访问,实现此接口的bean可以通过setApplicationContext(ApplicationContext context)
方法获得ApplicationContext
的引用。 - MessageSourceAware: 实现此接口的bean可以获得对
MessageSource
的引用,这允许bean进行国际化消息的处理,通过setMessageSource(MessageSource messageSource)
方法注入。 - ApplicationEventPublisherAware: 实现此接口的bean可以获得一个
ApplicationEventPublisher
的引用,用于发布应用事件,Spring会在适当时刻调用setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)
方法。 - ResourceLoaderAware: 实现此接口的bean可以获得对
ResourceLoader
的引用,这使得bean可以加载资源,如配置文件等,通过setResourceLoader(ResourceLoader resourceLoader)
方法注入。 - EnvironmentAware: 实现此接口的bean可以获得对当前应用环境的
Environment
对象的引用。这允许bean查询配置的属性、配置文件等,通过setEnvironment(Environment environment)
方法注入。 - EmbeddedValueResolverAware: 实现此接口的bean可以获得对字符串值解析器的引用,该解析器能够处理占位符(如
${...}
),通过setEmbeddedValueResolver(StringValueResolver resolver)
方法注入。 - SchedulingConfigurerAware (不直接属于
Aware
接口系列, 但类似): 允许配置计划任务,在Spring Boot应用中,可以通过实现SchedulingConfigurer
接口和覆盖configureTasks(ScheduledTaskRegistrar taskRegistrar)
方法来定义计划任务。
代码案例
下面列举举个常见的Aware
子类实现案例。
BeanFactoryAware接口
BeanFactoryAware
接口允许一个bean在初始化时获得对BeanFactory
的引用,这通常用于需要以编程方式访问其他bean或执行与容器相关的操作的场景。下面是一个简单的例子,演示了BeanFactoryAware
接口使用,如下代码:
先创建一个实现了BeanFactoryAware
接口的类:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component; @Component
public class MyBeanFactoryAwareBean implements BeanFactoryAware { private BeanFactory beanFactory; // 实现BeanFactoryAware接口的回调方法 @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; } // 一个简单的方法,用于从BeanFactory中获取bean public Object getBean(String beanName) { return beanFactory.getBean(beanName); }
}
然后,创建一个简单的bean,后面将通过MyBeanFactoryAwareBean
来获取它:
import org.springframework.stereotype.Component; @Component
public class MySimpleBean { public String sayHello() { return "Hello from MySimpleBean!"; }
}
接下来,创建一个配置类来启动Spring应用:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan(basePackages = "com.example") // 假设上面的类在com.example包下
public class AppConfig { // 这里不需要额外的bean定义,因为@Component注解已经足够
}
最后,编写一个客户端类来运行应用并测试MyBeanFactoryAwareBean
:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class ClientApp { public static void main(String[] args) { // 创建一个Spring应用上下文 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 获取MyBeanFactoryAwareBean的实例 MyBeanFactoryAwareBean beanFactoryAwareBean = context.getBean(MyBeanFactoryAwareBean.class); // 使用MyBeanFactoryAwareBean来获取MySimpleBean的实例 MySimpleBean simpleBean = (MySimpleBean) beanFactoryAwareBean.getBean("mySimpleBean"); // 调用MySimpleBean的方法并打印结果 System.out.println(simpleBean.sayHello()); // 关闭应用上下文 ((AnnotationConfigApplicationContext) context).close(); }
}
ApplicationContextAware接口
ApplicationContextAware
接口允许一个bean在初始化时获得对ApplicationContext
的引用,通常用于需要以编程方式访问其他bean或执行与Spring应用上下文相关的操作的场景。
如下代码,演示了如何实现ApplicationContextAware
接口,并在客户端代码中调用该bean。
首先,创建一个实现了ApplicationContextAware
接口的类:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component; @Component
public class MyApplicationContextAwareBean implements ApplicationContextAware { private ApplicationContext applicationContext; // 实现ApplicationContextAware接口的回调方法 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } // 一个简单的方法,用于从ApplicationContext中获取bean public Object getBean(String beanName) { return applicationContext.getBean(beanName); }
}
然后,创建一个简单的bean,稍后将通过MyApplicationContextAwareBean
来获取它:
import org.springframework.stereotype.Component; @Component
public class MySimpleBean { public String sayHello() { return "Hello from MySimpleBean!"; }
}
接下来,创建一个配置类来启动Spring应用:
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; @Configuration
@ComponentScan(basePackages = "com.example") // 假设上面的类在com.example包下
public class AppConfig { // 这里不需要额外的bean定义,因为@Component注解已经足够
}
最后,编写一个客户端类来运行应用并测试MyApplicationContextAwareBean
:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class ClientApp { public static void main(String[] args) { // 创建一个Spring应用上下文 ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 获取MyApplicationContextAwareBean的实例 MyApplicationContextAwareBean contextAwareBean = context.getBean(MyApplicationContextAwareBean.class); // 使用MyApplicationContextAwareBean来获取MySimpleBean的实例 MySimpleBean simpleBean = (MySimpleBean) contextAwareBean.getBean("mySimpleBean"); // 调用MySimpleBean的方法并打印结果 System.out.println(simpleBean.sayHello()); // 关闭应用上下文(尽管在这个例子中不是必须的,因为main方法结束后JVM会退出) ((AnnotationConfigApplicationContext) context).close(); }
}
EnvironmentAware接口
EnvironmentAware
接口允许bean在其初始化之后访问到Environment
属性。
Environment
表示当前应用环境,它封装了应用程序环境的配置属性,例如系统属性、环境变量以及应用上下文中的属性。
如下代码,演示了如何实现Environment
接口。
创建一个类MyEnvironmentAwareBean
实现EnvironmentAware
接口:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.EnvironmentAware;
import org.springframework.context.EnvironmentAwareBean;
import org.springframework.core.env.Environment; public class MyEnvironmentAwareBean implements EnvironmentAware { private Environment environment; // 实现 EnvironmentAware 接口的 setEnvironment 方法 @Override public void setEnvironment(Environment environment) throws BeansException { this.environment = environment; } // 一个简单的方法,用于输出某个属性的值 public void printProperty(String propertyName) { String propertyValue = environment.getProperty(propertyName); System.out.println("Property '" + propertyName + "' = " + propertyValue); }
}
上面的代码中MyEnvironmentAwareBean
类实现了EnvironmentAware
接口,并通过setEnvironment
方法接收Environment
对象。
接下来,配置Spring上下文,注册MyEnvironmentAwareBean
bean,并通过一个客户端类调用它:
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; @Configuration
public class AppConfig { // 声明 MyEnvironmentAwareBean 为一个 bean @Bean public MyEnvironmentAwareBean myEnvironmentAwareBean() { return new MyEnvironmentAwareBean(); }
} public class ClientApp { public static void main(String[] args) { // 创建 AnnotationConfigApplicationContext 上下文 AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); // 从上下文中获取 MyEnvironmentAwareBean 实例 MyEnvironmentAwareBean myBean = context.getBean(MyEnvironmentAwareBean.class); // 调用 printProperty 方法,打印系统属性 java.version myBean.printProperty("java.version"); // 关闭上下文 context.close(); }
}
ResourceLoaderAware接口
如下代码,演示了如何实现Environment
接口:
创建一个类MyResourceLoaderAwareComponent
实现ResourceLoaderAware
接口,并实现setResourceLoader
方法
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component; import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Scanner; // 声明这是一个Spring组件
@Component
public class MyResourceLoaderAwareComponent implements ResourceLoaderAware { private ResourceLoader resourceLoader; // 实现了ResourceLoaderAware接口的setResourceLoader方法 @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } // 使用ResourceLoader加载资源并返回资源内容 public String loadResourceContent(String location) { Resource resource = resourceLoader.getResource(location); try (InputStream inputStream = resource.getInputStream(); Scanner scanner = new Scanner(inputStream, StandardCharsets.UTF_8.name())) { StringBuilder content = new StringBuilder(); while (scanner.hasNextLine()) { content.append(scanner.nextLine()).append("\n"); } return content.toString(); } catch (IOException e) { throw new RuntimeException("Failed to load resource: " + location, e); } }
}
创建换一个client类MyResourceLoaderAwareClient
,类中通过@Autowired
将MyResourceLoaderAwareComponent
注入进来,如下:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class MyResourceLoaderAwareClient { private final MyResourceLoaderAwareComponent myResourceLoaderAwareComponent; @Autowired public MyResourceLoaderAwareClient(MyResourceLoaderAwareComponent myResourceLoaderAwareComponent) { this.myResourceLoaderAwareComponent = myResourceLoaderAwareComponent; } // 客户端方法,用于调用加载资源的方法并打印结果 public void printResourceContent(String location) { String content = myResourceLoaderAwareComponent.loadResourceContent(location); System.out.println("Resource content from location: " + location); System.out.println(content); }
}
最后,Aware
子类比较多,这里就不一一通过代码举例了,但是只需要记住,在Spring中提供的Aware
接口都是为了能够让开发者轻松地获取到Spring容器中的其他资源的引用。
END!
END!
END!
往期回顾
精品文章
Spring揭秘:@import注解应用场景及实现原理!
Java并发基础:原子类之AtomicMarkableReference全面解析!
Java并发基础:concurrent Flow API全面解析
Java并发基础:CopyOnWriteArraySet全面解析
Java并发基础:ConcurrentSkipListMap全面解析
相关文章:

Spring揭秘:Aware接口应用场景及实现原理!
内容概要 Aware接口赋予了Bean更多自感知的能力,通过实现不同的Aware接口,Bean可以轻松地获取到Spring容器中的其他资源引用,像ApplicationContext、BeanFactory等。 这样不仅增强了Bean的功能,还提高了代码的可维护性和扩展性&…...

校园小情书微信小程序,社区小程序前后端开源,校园表白墙交友小程序
功能 表白墙卖舍友步数旅行步数排行榜情侣脸漫画脸个人主页私信站内消息今日话题评论点赞收藏 效果图...
从Pandas到Polars :数据的ETL和查询
对于我们日常的数据清理、预处理和分析方面的大多数任务,Pandas已经绰绰有余。但是当数据量变得非常大时,它的性能开始下降。 本文将介绍如何将日常的数据ETL和查询过滤的Pandas转换成polars。 图片 Polars的优势 Polars是一个用于Rust和Python的Data…...

Node.Js编码注意事项
Node.js 中不能使用 BOM 和 DOM 的 API,可以使用 console 和定时器 APINode.js 中的顶级对象为 global,也可以用 globalThis 访问顶级对象 浏览器端js的组成 Node.js中的JavaScript组成 相比较之下发现只有console与定时器是两个API所共有的ÿ…...

floodfill算法题目
前言 大家好,我是jiantaoyab,在下面的题目中慢慢体会floodFill算法,虽然是新的算法,但是用的思想和前面的文章几乎一样,代码格式也几乎一样,但不要去背代码 图像渲染 https://leetcode.cn/problems/flood…...

AI相关的实用工具分享
AI实用工具大赏:赋能科研与生活,探索AI的无限可能 前言 在数字化浪潮汹涌而至的今天,人工智能(AI)已经渗透到我们生活的方方面面,无论是工作还是生活,都在悄然发生改变。AI的崛起不仅为我们带…...

K8s — PVC|PV Terminating State
在本文中,我们将讨论PV和PVC一直Terminating的状态。 何时会Terminting? 在以下情况下,资源将处于Terminating状态。 在删除Bounded 状态的PVC之前,删除了对应的PV,PV在删除后是Terminting状态。删除PVC时,仍有引用…...

C语言 --- 指针(5)
目录 一.sizeof和strlen对比 1.sizeof 2.strlen 3.strlen 和sizeof的对比 二.数组和指针笔试题目详解 回顾:数组名的理解 1.一维数组 2.字符数组 代码1: 代码2: 代码3: 代码4: 代码5: 代码6&am…...

Android Studio Iguana | 2023.2.1版本
Android Gradle 插件和 Android Studio 兼容性 Android Studio 构建系统基于 Gradle,并且 Android Gradle 插件 (AGP) 添加了一些特定于构建 Android 应用程序的功能。下表列出了每个版本的 Android Studio 所需的 AGP 版本。 如果特定版本的 Android Studio 不支持…...

并查集(蓝桥杯 C++ 题目 代码 注解)
目录 介绍: 模板: 题目一(合根植物): 代码: 题目二(蓝桥幼儿园): 代码: 题目三(小猪存钱罐): 代码: …...

MapReduce内存参数自动推断
MapReduce内存参数自动推断。在Hadoop 2.0中,为MapReduce作业设置内存参数非常繁琐,涉及到两个参数:mapreduce.{map,reduce}.memory.mb和mapreduce.{map,reduce}.java.opts,一旦设置不合理,则会使得内存资源浪费严重&a…...
pyside6 pytq PyDracula QVideoWidget视频只有画面没有声音
解决方案: 先不使用框架,纯pyside6代码,如果添加视频有画面有声音,那可以排除是硬件问题,如果没有画面只有声音,可能是视频解码器无法解码,换个格式的视频文件如果只有使用PyDracula 出问题&am…...

Axure基础 各元件的作用及介绍
图像热区 增加按钮或者文本的点击区域,他是透明的,在预览时看不见。 动态面板 用来绘制一下带交互效果的元件,他是动态的,如轮播图,一个动态面板里可以有多个子面板,每一个子面板对应着不同的效果。 他…...

学习Java的第六天
目录 一、变量 1、变量的定义 2、变量的声明格式 3、变量的注意事项 4、变量的作用域 二、常量 三、命名规范 Java 语言支持如下运算符: 1、算术运算符 解析图: 示例: 2、赋值运算符 解析图: 示例: 3、关…...

基于Spring Boot+ Vue的房屋租赁系统
末尾获取源码作者介绍:大家好,我是墨韵,本人4年开发经验,专注定制项目开发 更多项目:CSDN主页YAML墨韵 学如逆水行舟,不进则退。学习如赶路,不能慢一步。 目录 一、项目简介 二、开发技术与环…...
多轨迹建模方法的介绍与实操-基于R语言
本文介绍了多轨迹建模方法(Group-Based Multivariate Trajectory Modeling),这是一种扩展了单指标组基轨迹建模的技术,用于分析多个疾病生物标志物或临床重要因素的联合轨迹,以更好地理解和追踪疾病进程、行为或健康状…...

【Spring】Spring状态机
1.什么是状态机 (1). 什么是状态 先来解释什么是“状态”( State )。现实事物是有不同状态的,例如一个自动门,就有 open 和 closed 两种状态。我们通常所说的状态机是有限状态机,也就是被描述的事物的状态的数量是有…...
Node.js基础---使用Express写接口
1. 创建基本的服务器 2. 创建 API 路由模块 // aoiRouter.js 路由模块 const express require(express) const apiRouter express.Router()module.exports apiRouter// ------------------------------------------// app.js 导入并注册路由模块 const apiRouter require(…...
小蓝的钥匙(蓝桥杯错排)
现在有28个小朋友,每个人手上有一把钥匙,每一个钥匙都只能打开自己的房间门,现在将所有钥匙都收上来,然后再随机打乱分给每个小朋友,也就是有28!的分法,请问现在其中14个小朋友的钥匙能恰好打开…...

【Python】科研代码学习:八 FineTune PretrainedModel (用 trainer,用 script);LLM文本生成
【Python】科研代码学习:八 FineTune PretrainedModel [用 trainer,用 script] LLM文本生成 自己整理的 HF 库的核心关系图用 trainer 来微调一个预训练模型用 script 来做训练任务使用 LLM 做生成任务可能犯的错误,以及解决措施 自己整理的 …...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁
赛门铁克威胁猎手团队最新报告披露,数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据,严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能,但SEMR…...