聊聊Spring的Aware接口

文章目录

  • 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;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}public double calculateInterest(String accountId, double principal, double rate, double time) {// 通过 applicationContext 获取 Spring 容器中的 AccountService beanAccountService 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;@Overridepublic 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.rhkb.cn/news/137606.html

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

相关文章

Spring Boot魔法:简化Java应用的开发与部署

文章目录 什么是Spring Boot?1. 自动配置(Auto-Configuration)2. 独立运行(Standalone)3. 生产就绪(Production Ready)4. 大量的起步依赖(Starter Dependencies) Spring …

【SpringMVC】JSR 303与interceptor拦截器快速入门

目录 一、JSR303 1、什么是JSR 303? 2、为什么要使用JSR 303? 3、JSR 303常用注解 3.1、常用的JSR 303注解 3.2、Validated与Valid区别 3.2.1、Validated 3.2.2、Valid 3.2.3、区别 4、使用案例 4.1、导入依赖 4.2、配置校验规则 4.3、编写…

大模型Tuning分类

类型总结 微调(Fine-tunning) 语言模型的参数需要一起参与梯度更新 轻量微调(lightweight fine-tunning) 冻结了大部分预训练参数,仅添加任务层,语言模型层参数不变 适配器微调 (Adapter-t…

数据研发“新人”如何快速落地?

作者:肖迪(墨诩) 一、前言 这个季度主推安全月构筑&夯实稳定性底盘,就组织了组里的同学对核心业务链路进行了稳定性的摸排。在摸排过程中,不断有个声音在问你摸排出来的问题就是全部问题么?你加的监控加全了么?你…

进程同步与互斥

目录 进程同步与互斥(1) 第一节、进程间相互作用 一、相关进程和无关进程 二、与时间有关的错误 第二节、进程同步与互斥 一、进程的同步 二、进程的互斥 三、临界区 进程同步与互斥(2) 三、信号量与P、V操作的物理含义…

Tomcat 下部署 jFinal

1、检查web.xml 配置&#xff0c;在 tomcat 下部署需要检查 web.xml 是否存在&#xff0c;并且要确保配置正确&#xff0c;配置格式如下。 <?xml version"1.0" encoding"UTF-8"?> <web-app xmlns:xsi"http://www.w3.org/2001/XMLSchema-i…

使用命令行(CMD)编译单Java文件

1.安装JDK JDK官网&#xff1a;https://www.oracle.com/java/technologies/downloads/ 选 Windows -> x64 MSI Instaler或者x64 Installer 安装成功后。 2.配置环境变量 按下Win键&#xff0c;搜索环境变量 添加JAVA_HOME系统环境变量&#xff0c;要指定类似这样的路径(…

Dubbo学习(一)——dubbo学习背景

文章目录 前言分布式基础理论什么是分布式系统发展演变ORMMVCRPCSOA RPC(远程调用)什么是RPCRPC工作原理 为什么RPC要用到DubboDubbo的优势高性能可扩展性高可靠性监控和管理 使用示例总结 前言 分布式基础理论 什么是分布式系统 分布式系统是若干独立计算机的集合&#xff…

月木学途开发 1.后台用户模块

概述 权限控制采用springsecurity 数据库设计 用户表 DROP TABLE IF EXISTS admin; CREATE TABLE admin (aid int(32) NOT NULL AUTO_INCREMENT,email varchar(50) DEFAULT NULL,username varchar(50) DEFAULT NULL,password varchar(255) DEFAULT NULL,phoneNum varchar(2…

在Ubuntu 18.04上支持C++17的std::filesystem的方法

在Ubuntu 18.04上通过命令sudo apt install gcc g安装的gcc/g版本为7.5&#xff0c;此版本并不直接支持filesystem&#xff0c;如下图所示&#xff1a; Ubuntu 18.04上的g 7.5支持experimental的filesystem,即std::experimental::filesystem&#xff0c;若想使Ubuntu 18.04支持…

软件设计原则扩展

一、引言 经典的软件设计7大原则 开闭原则&#xff08;Open Close Principle, OCP&#xff09; 依赖倒置原则&#xff08;Dependence Inversion Principle, DIP&#xff09; 单一职责原则&#xff08;Simple Responsibility Principle, SRP&#xff09; 接口隔离原则&#xf…

OPENCV实现DNN图像分类

使用步骤1 使用步骤2 使用步骤3 使用步骤4 使用步骤5 使用步骤6 完整代码如下: import numpy as np

Git --- 基础介绍

Git --- 基础介绍 git 是什么git --- 工作区, 暂存区, 资源库git --- 文件状态git --- branch 和 HEADgit --- 一次正常的git提交流程 git 是什么 Git是一款分布式源代码管理工具(版本控制工具)Git和其他传统版本控制系统比较: 传统的版本控制系统(例如 SVN)是基于差异的版本控…

从零开始学习 Java:简单易懂的入门指南之Stream流(二十七)

Stream流 Stream流1.体验Stream流2.Stream流的常见生成方式3.Stream流中间操作方法4.Stream流终结操作方法5.Stream流的收集操作6.Stream流综合练习 Stream流 1.体验Stream流 案例需求 按照下面的要求完成集合的创建和遍历 创建一个集合&#xff0c;存储多个字符串元素把集合中…

ElasticSearch(ES)简单介绍

ES简介 Elasticsearch&#xff08;通常简称为ES&#xff09;是一个开源的分布式搜索和分析引擎&#xff0c;旨在处理各种类型的数据&#xff0c;包括结构化、半结构化和非结构化数据。它最初是为全文搜索而设计的&#xff0c;但随着时间的推移&#xff0c;它已经演变成一个功能…

后端返回的id到前端后 后面几位数全部变成0了 问题解决

这里 我在java控制台上 输出了id的值 但请求到前端后 很明显就不太一样了 这个问题比较经典的叫法是 雪花算法生成的ID过长&#xff0c;前端接收精度丢失 原因 前端使用number类型进行接收&#xff0c;number类型的范围小于后台Long类型的范围&#xff0c;出现了精度丢失问题…

【Vue】路由与Node.js下载安装及环境配置教程

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Vue快速入门》。&#x1f3af;&#x1f3af; &…

界面控件DevExpress WinForms HTML-CSS模板:预设计UI模板加速.NET应用开发

在过去的一年里&#xff0c;DevExpress官方引入了两个强大的功能来加速/简化.NET桌面应用的开发&#xff0c;当一起使用时&#xff0c;您可以创建优雅/个性化的用户界面&#xff0c;减少重复的代码&#xff0c;从而节省更多的项目时间。 DevExpress WinForms有180组件和UI库&am…

2023_Spark_实验十二:Spark高级算子使用

掌握Spark高级算子在代码中的使用 相同点分析 三个函数的共同点&#xff0c;都是Transformation算子。惰性的算子。 不同点分析 map函数是一条数据一条数据的处理&#xff0c;也就是&#xff0c;map的输入参数中要包含一条数据以及其他你需要传的参数。 mapPartitions函数是一个…

公开研讨会|智能制造中生产管理挑战与解决方案(9月29日)

随着新能源行业的规模化发展&#xff0c;企业增效降本成为迫切需求。生产制造能力成为关键因素&#xff0c;其发展必将是在大规模生产的前提下&#xff0c;追寻极简制造、极限制造以及智能制造。然而在这个发展过程中&#xff0c;企业依旧面临着诸多挑战&#xff1a; 产品设计…