聊聊Spring的Aware接口

news2024/11/23 11:35:51

文章目录

  • 0.前言
  • 1.什么是Aware接口
  • 2.Aware接口的设计目的
  • 3.详解
    • 3.1. `ApplicationContextAware`
      • 我们举个例子来说明
    • 3.2. `BeanFactoryAware`
    • 3.3. `BeanNameAware`
    • 3.4. `ServletContextAware`
    • 3.5. `MessageSourceAware`
    • 3.6. `ResourceLoaderAware`
  • 4.参考文档

在这里插入图片描述

0.前言

背景: 最近有开发同学问我项目里面有很多地方实现了Aware 接口,到底是什么作用。他说这个原因是在我们的工程代码中看到有一些代码里实现了ResourceLoaderAware、BeanNameAware、ApplicationContextAware、BeanFactoryAware接口。我没法直接笼统回答,也没有法一句话简答,只好侧面的告诉他Aware接口是Spring 为了提供拓展的一种设计思想。凡是带Aware后缀的接口。主要作用是为了让实现了该接口的Bean在Spring容器中具有回调功能。通过实现不同子接口,可以让Bean在运行过程中获取Spring容器内部的一些特定对象

为了进一步论证我给的答案,今天抽时间把项目里面的Aware的实现或者间接实现的类大概看了一下。包含Spring框架和第三方框架在内,大概有673个实现使用到。
在这里插入图片描述

1.什么是Aware接口

我们先来看一下所有Aware接口的超接口的定义org.springframework.beans.factory.Aware
在这里插入图片描述
根据注释我们可以了解到 org.springframework.beans.factory.Aware 标记超接口,指示一个Bean有资格通过回调方式接收Spring容器传递的特定框架对象。实际的方法签名由各个子接口决定,但通常应该只包含一个接受单一参数的返回void的方法。这个翻译有点抽象 通俗的说 这个Aware接口是Spring框架中的一个机制,允许Bean通过回调方式与Spring容器进行交互,并获取特定的框架对象,以便在Bean的逻辑中进行相应的处理

Spring框架中有一系列的Aware接口,这些接口是用于让实现它们的Bean获得一些Spring框架的对象或资源,这些资源包括ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher等等。

Aware接口名称通常是以Aware结尾,例如最常见的ApplicationContextAware和BeanFactoryAware,它们分别可以让Bean获得ApplicationContext和BeanFactory。

例如,如果一个Bean实现了ApplicationContextAware接口,那么在Spring创建这个Bean的时候,会自动调用setApplicationContext方法,将ApplicationContext作为参数传入,这样这个Bean就可以在运行时获取到Spring的ApplicationContext。

通常并不建议直接使用Aware接口,因为这样会导致代码与Spring框架耦合过于紧密。在大多数情况下,我们可以通过依赖注入或者其他更好的方式来获取Spring框架的资源。除非为了实现特定功能,我们才会实现对应的Aware接口来获取资源。

2.Aware接口的设计目的

这样设计的目的是为了让Bean可以与Spring框架的其他部分相互作用,而不是仅仅被动地接受由Spring容器创建和管理。

我觉得这样的设计 还有一个好处 。可以直接通过名称+Aware后缀就可以知道这个Aware接口具备的能力。可以直接获取或操作Spring框架的一些资源,换句话来讲,其实也是Spring的格局比较高 使得Spring框架“让普通Java对象能够使用框架的全功能”的一种体现。

所以,通常来说,接口名的规则是:[感知/获得的资源或环境] + Aware例如BeanFactoryAwareResourceLoaderAware
在这里插入图片描述

我们观察一下Aware接口及其子接口的命名规则很简单,通常是在Aware后面添加相应的功能名。这些功能名通常代表了实现该接口的类需要获得的资源或者感知的环境。例如:

  • ApplicationContextAware:意味着实现该接口的类可以感知到应用上下文(ApplicationContext)。

  • BeanFactoryAware:实现该接口的类可以感知到Bean工厂(BeanFactory)。

  • BeanNameAware:实现该接口的类可以感知到Bean的名字。

  • ServletContextAware意味着实现该接口的类可以感知到Servlet上下文(ServletContext)。

  • MessageSourceAware:实现该接口的类可以感知到消息源(MessageSource)。

-ResourceLoaderAware:实现该接口的类可以感知到资源加载器(ResourceLoader)。

3.详解

我们分别来了解一下这些常见的Aware接口的使用场景和用法 ApplicationContextAwareBeanFactoryAwareBeanNameAwareServletContextAwareMessageSourceAwareResourceLoaderAware

3.1. ApplicationContextAware

这个接口我们太常见了。几乎大多数项目中都会用到。因为它能取到。它会在一个类需要访问Spring应用上下文中的所有服务(例如其他bean,生命周期事件,特定配置等)时被实现。

ApplicationContextAware 是 Spring 框架的一个接口,当一个类实现了这个接口,那么这个类就会具备访问 Spring ApplicationContext 的能力。也就是说,这个类可以直接获取到 spring 容器中的所有 bean。

这个接口主要有一个方法:setApplicationContext(ApplicationContext applicationContext)。Spring 容器会检测所有 bean,如果发现某个 bean 实现了 ApplicationContextAware 接口,Spring 容器就会在创建该 bean 后,自动调用这个 bean 的 setApplicationContext(ApplicationContext applicationContext) 方法,调用该方法时,会将容器本身作为参数传给该 bean。这样,当 bean 需要使用容器的功能时,就可以使用这个传入的参数。

这个接口通常在需要访问容器本身的功能,或者需要访问容器中的其他 bean 时使用。例如,当 bean 需要动态地查找其他 bean,或者需要使用容器的发布事件功能时,就可以通过实现这个接口来获取到容器对象。

一般情况下,我们不需要直接实现这个接口,因为 Spring 提供了 ApplicationObjectSupport 类,这个类实现了 ApplicationContextAware 接口,我们可以通过继承这个类来简化我们的代码。

我们举个例子来说明

下面是一个具体的计算服务示例,它使用 ApplicationContextAware 接口来获取一个账户服务。
CalculationService 类实现了 ApplicationContextAware 接口,并重写了 setApplicationContext 方法。当 Spring 容器创建 CalculationService 实例之后,就会自动调用 CalculationServicesetApplicationContext 方法,并将容器本身作为参数传入。
然后,CalculationService 就可以通过 applicationContext 成员变量来访问容器本身,从而获取到容器中的 AccountService,并使用该服务来进行利息计算。

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class CalculationService implements ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public double calculateInterest(String accountId, double principal, double rate, double time) {
        // 通过 applicationContext 获取 Spring 容器中的 AccountService bean
        AccountService accountService = applicationContext.getBean(AccountService.class);
        // 使用获取到的 AccountService 进行操作
        double interest = accountService.calculateInterest(principal, rate, time);
        return interest;
    }
}

3.2. BeanFactoryAware

当一个类需要访问Spring BeanFactory,以获得对Spring框架的底层访问时,会实现这个接口。

我们举个例子来理解一下,比如我们大多项目都会发送通知,可能需要邮件,微信,短信,飞书这些,这些配置可以允许用户自定义配置,后续系统还可能扩展钉钉等其他类型通知。为了满足这个需求。我们利用 BeanFactoryAware 创建一个服务定位器(Service Locator)。服务定位器用于集中管理和查找服务。在复杂的应用中,这可以使代码更容易管理和扩展。

首先考虑我们有许多服务,如 EmailServiceSMSServicePushNotificationService 等,都实现了一个 MessageService 接口。我们可以使用 BeanFactoryAware 来创建一个服务定位器,能够根据需要获取任何服务。

@Service
public class ServiceLocator implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public MessageService getService(String serviceName) {
        return (MessageService) beanFactory.getBean(serviceName);
    }
}

然后在需要服务的地方,我们可以这样使用:

@Service
public class MessageClient {

    private final ServiceLocator serviceLocator;

    public MessageClient(ServiceLocator serviceLocator) {
        this.serviceLocator = serviceLocator;
    }

    public void sendMessage(String message, String serviceName) {
        MessageService service = serviceLocator.getService(serviceName);
        service.send(message);
    }
}

ServiceLocator 通过实现 BeanFactoryAware 接口,可以获取到 Spring 容器,然后根据服务名获取相应的服务。MessageClient 通过 ServiceLocator 可以灵活地选择需要的服务,使得代码更加灵活和可测试。

剩下这四个也很常见,明天有时间再搞吧,今天太晚了就到这

3.3. BeanNameAware

当一个类需要知道在Spring配置中定义的它的bean名称时,会实现这个接口。

3.4. ServletContextAware

这个接口会在一个类需要获取到ServletContext,通常用在需要访问Servlet API的web应用中时被实现。例如,需要读取web应用中的某些real path,或者servlet context attributes等。

3.5. MessageSourceAware

当一个类需要加载一些消息资源,如一些国际化的字符串时,会实现这个接口。

3.6. ResourceLoaderAware

当一个类需要加载一些文件资源时,会实现这个接口。这可以让你更方便的加载classpath或者文件系统中的资源。

4.参考文档

  1. Spring 官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-aware
  2. Spring 框架 API 文档(有关 BeanFactoryAware 的部分):https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/BeanFactoryAware.html
  3. 关于服务定位器模式的解释:https://www.martinfowler.com/eaaCatalog/serviceLocator.html
  4. 使用 Spring 实现服务定位器模式的示例:https://www.baeldung.com/spring-service-locator

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

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

相关文章

C语言数组和指针笔试题(三)(一定要看)

目录 字符数组四例题1例题2例题3例题4例题5例题6例题7 结果字符数组五例题1例题2例题3例题4例题5例题6例题7结果字符数组六例题1例题2例题3例题4例题5例题6例题7 结果 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 🐒🐒🐒个…

建构居住安全生态,鹿客科技2023秋季发布会圆满举办

9月20日,以「Lockin Opening」为主题的2023鹿客秋季发布会在上海隆重举办,面向居住安全领域鹿客带来了最新的高端旗舰智能锁新品、多眸OS1.0、Lockin Care服务以及全联接OPENING计划。此外,现场还邀请了国家机构、合作伙伴、技术专家等业界同…

ai智能生成文章-智能生成文章软件

您是否曾为创作内容而感到头疼不已?是否一直在寻找一种能够帮助您轻松生成高质量文章的解决方案?什么是AI智能生成文章,特别是147SEO智能原创文章生成。这是一种先进的技术,利用人工智能和自然语言处理,能够自动生成各…

Ant Design分页组件中实现禁止点击当前页按钮的方法

这里需要使用到Ant Design分页组件pagination的一个回调函数onChange onChange函数用来监听鼠标点击事件, 它有两个入参》1. 点击分页按钮时获取到的页码 2. 每页最大显示条数 所以,禁止点击当前分页按钮的核心逻辑是: if {当前页的页…

mybatis-plus异常:dynamic-datasource can not find primary datasource

现象 使用mybatis-plus多数据源配置时出现异常 com.baomidou.dynamic.datasource.exception.CannotFindDataSourceException: dynamic-datasource can not find primary datasource分析 异常原因是没有设置默认数据源,在类上没有使用DS指定数据源时,默…

批量、在线学习, 参数、非参数学习

批量学习(Batch Learning)和在线学习(Online Learning) 批量学习 批量学习的概念非常容易理解,我们之前介绍的许多机器学习算法,如果没有特殊说明,都可以采用批量学习的方式。批量学习的过程通…

网络安全——(黑客)自学

想自学网络安全(黑客技术)首先你得了解什么是网络安全!什么是黑客!!! 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队…

react多条件查询

1、声明一个filter常量 2.filter接受(condition,data)两个参数 3、调用data里面的filter进行筛选 4、任意一个item当筛选条件 5、使用object.key获取对象所有key 6、对每个key使用Array.prototype.every()方法判断是否满足条…

pom.xml中解决“vulnerable dependency maven:org.yaml:snakeyaml:1.33“警告问题

问题 当我们引入依赖的时候,pom文件会有这样的提示,其大概的意思就是 maven:org.yaml:snakeyaml:1.30"表示通过Maven引入了一个潜在的安全漏洞依赖项"org.yaml:snakeyaml:1.30" 解决办法 其实我们就是要更改这个依赖的版本&#xff0c…

Linux高性能服务器编程 学习笔记 第七章 Linux服务器程序规范

除了网络通信外,服务器程序通常还需考虑许多其他细节问题,这些细节问题涉及广而零碎,且基本上是模板式的,我们称之为服务器程序规范,如: 1.Linux服务器程序一般以后台进程形式运行,后台进程又称…

AI智能文案写作工具,迅速生成高质量的文案

大家好,欢迎来到这篇文章。在信息时代,文字的力量愈发重要,无论是用于广告、文章还是社交媒体,优质的文案都能够吸引更多的注意力。但是,对于许多人来说,创作文案可能是一项繁琐且耗时的任务。 147GPT批量文…

黑马JVM总结(二十三)

(1)字节码指令-init 方法体内有一些字节,对应着将来要由java虚拟机执行方法内的代码,构造方法里5个字节代码,main方法里有9个字节的代码 java虚拟机呢内部有一个解释器,这个解释器呢可以识别平台无关的字…

【算法】滑动窗口破解长度最小子数组

Problem: 209. 长度最小的子数组 文章目录 题意分析算法原理讲解暴力枚举O(N^2)利用单调性,滑动窗口求解 复杂度Code 题意分析 首先来分析一下本题的题目意思 题目中会给到一个数组,我们的目的是找出在这个数组中 长度最小的【连续】子数组,而…

Android滑动片段

本文所有的代码均存于 https://github.com/MADMAX110/BitsandPizzas 回到BitsandPizzas应用,之前已经创建过创建订单和发出反馈等功能。 修改披萨应用,让它使用标签页导航。在工具条下显示一组标签页,每个选项对应一个不同的标签页。用户单击…

asrpro 天问BLOCK 总结

ASRPRO芯片信息 主频240MHz 640KByte SRAM 2-4M FLASH (https://haohaodada.com/jpeguploadfile/twen/ASRPRO/asr_pro_core.pdf) 下载 (注意最好用好点的USB转TTL或是网方的下载器,否则会怀疑人生) 下载程序步骤 安装VSCODE 在字符模式下&a…

微服务架构设计:构建高可用性和弹性的应用

文章目录 引言微服务架构的基本概念1. 服务单元2. 通信机制3. 自动化部署4. 增量升级5. 监控和日志 设计原则1. 单一职责原则2. 松散耦合3. 有界上下文4. 弹性设计5. API 设计 优势和挑战优势挑战 实际案例:Netflix结论 🎉欢迎来到架构设计专栏~探索Java…

2020年06月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python编程(1~6级)全部真题・点这里 一、单选题(共25题,每题2分,共50分) 第1题 下面程序执行完毕后,最终的结果是?( ) a[34,17,7,48,10,5] b[] c[] while …

Aqs独占/共享模式

独占锁和共享锁的概念 独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。 共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共…

039_小驰私房菜_Camera perfermance debug

全网最具价值的Android Camera开发学习系列资料~ 作者:8年Android Camera开发,从Camera app一直做到Hal和驱动~ 欢迎订阅,相信能扩展你的知识面,提升个人能力~ 一、抓取trace 1. adb shell "echo vendor.debug.trace.perf=1 >> /system/build.prop" 2. …

栈和队列-Java

目录 一、栈 1.1 概念 1.2 栈的使用 1.3 栈的模拟实现 1.4 栈的应用场景 1.5 概念区分 二、队列 2.1 概念 2.2 队列的使用 2.3 队列的模拟实现 2.4 循环队列 三、双端队列 四、面试题 一、栈 1.1 概念 栈:一种特殊的线性表,只允许在固定的一端进行插…