Spring揭秘:ApplicationContextAware应用场景及实现原理!

Spring揭秘:ImportBeanDefinitionRegistrar应用场景及实现原理! - 程序员古德

内容概要

ApplicationContextAware接口能够轻松感知并在Spring中获取应用上下文,进而访问容器中的其他Bean和资源,这增强了组件间的解耦,了代码的灵活性和可扩展性,是Spring框架中实现高级功能的关键接口之一。

核心概念

它能用来干啥?

为了方便理解,模拟一个业务场景。假如有一个功能模块负责处理订单,在这个模块中,有一个OrderService类,它负责订单的创建、更新和查询等操作,单在处理订单的过程中,可能需要访问其他一些服务,比如用户服务来获取用户信息,或者库存服务来检查商品库存。

在这个场景中,可以使用ApplicationContextAware接口来解决,可以创建一个类,比如叫OrderServiceContextAware,让它实现ApplicationContextAware接口,当Spring容器初始化这个类时,它会自动将应用上下文注入到这个类中,一旦注入了应用上下文,OrderServiceContextAware就能够访问到容器中的其他Bean,包括用户服务和库存服务。

可以在OrderService类中使用OrderServiceContextAware来获取用户服务和库存服务的实例,而无需直接在OrderService中注入这些服务,这样OrderService类不直接依赖于其他服务的具体实现,而是通过OrderServiceContextAware来间接访问这些服务。

它有哪些特性?

ApplicationContextAware是Spring框架提供的一个特殊的回调接口,用于帮助对象(特别是普通的Java Bean)访问到Spring的应用上下文ApplicationContext

当在自己的类中实现ApplicationContextAware接口时,可以通过Spring提供的回调机制访问到Spring的应用上下文,从而获得Spring IoC容器中的bean实例、配置信息以及进行国际化操作、事件发布等操作。

ApplicationContextAware接口中定义了一个setApplicationContext方法,当类实现了该接口之后,Spring IoC容器会自动调用该方法并将当前的ApplicationContext注入到所实现的setApplicationContext方法中,这样就可以在该类中使用Spring的应用上下文了。

在一些开源的Spring工具库中会看到这种技术的使用,因为这些库往往需要与Spring容器交互,比如读取容器的配置,访问其他的bean等等,通过实现ApplicationContextAware接口就可以非常方便地完成这些工作。

但注意,一般不推荐在的业务代码中使用,因为这样会增加代码与Spring的耦合性,违反了“依赖于抽象,而非依赖于具体实现”的面向对象设计原则。业务代码应当尽可能减少对具体框架的依赖,以提高代码的通用性和可移植性。

代码案例

下面是一个简单的代码案例,展示了如何使用ApplicationContextAware接口来创建一个能够访问Spring应用上下文的类,如下代码:

首先,创建一个实现ApplicationContextAware接口的类:

import org.springframework.beans.BeansException;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.ApplicationContextAware;  
import org.springframework.stereotype.Component;  @Component  
public class SpringContextUtil implements ApplicationContextAware {  // Spring应用上下文  private static ApplicationContext applicationContext;  // 当Spring容器创建该类的实例时,会自动调用此方法,注入应用上下文  @Override  public void setApplicationContext(ApplicationContext context) throws BeansException {  SpringContextUtil.applicationContext = context;  }  // 提供一个静态方法,返回应用上下文  public static ApplicationContext getApplicationContext() {  return applicationContext;  }  // 提供一个获取Bean的静态方法  public static <T> T getBean(Class<T> beanClass) {  if (applicationContext != null) {  return applicationContext.getBean(beanClass);  } else {  throw new IllegalStateException("ApplicationContext is not initialized yet!");  }  }  
}

接着,定义一个简单的服务类作为Spring Bean:

import org.springframework.stereotype.Service;  @Service  
public class DemoService {  public String sayHello() {  return "Hello from DemoService!";  }  
}

然后,可以使用Spring的Java配置或者XML配置来定义和初始化这些Bean,假设使用Java配置:

import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  @Configuration  
public class AppConfig {  @Bean  public SpringContextUtil springContextUtil() {  return new SpringContextUtil();  }  @Bean  public DemoService demoService() {  return new DemoService();  }  
}

最后,在客户端代码中,我们可以通过SpringContextUtil类来获取DemoService的实例并调用其方法:

import org.springframework.context.annotation.AnnotationConfigApplicationContext;  public class ApplicationClient {  public static void main(String[] args) {  // 创建Spring上下文,注册Java配置类  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);  // 关闭Spring上下文,以便能够正常结束程序(尽管在这个示例中可能不需要)  context.registerShutdownHook();  // 通过SpringContextUtil获取DemoService实例  DemoService demoService = SpringContextUtil.getBean(DemoService.class);  // 调用DemoService的sayHello方法  System.out.println(demoService.sayHello());  }  
}

输出结果:

复制代码Hello from DemoService!

以上代码展示了如何通过SpringContextUtil访问Spring的应用上下文,并获取其中的一个bean(DemoService)。

ApplicationClient类是客户端代码的入口点,它初始化了一个AnnotationConfigApplicationContext,通过它Spring可以创建和管理beans,随后客户端代码使用SpringContextUtil.getBean静态方法来获取DemoService的实例,并调用它的sayHello方法。

核心API

ApplicationContextAware接口是一个特殊的标记接口。

它允许实现类能够访问到ApplicationContext,即Spring的应用上下文,ApplicationContextAware中有且只有一个核心方法,如下是该方法的说明:

public interface ApplicationContextAware extends Aware {  void setApplicationContext(ApplicationContext applicationContext) throws BeansException;  
}

setApplicationContext方法的含义如下:

  • void setApplicationContext(ApplicationContext applicationContext) throws BeansException:
    这个方法会在Spring容器初始化的时候被自动调用,Spring容器会将当前的ApplicationContext作为参数传递给该方法,实现这个接口的类可以在这个方法中保存对ApplicationContext的引用,从而能够在后续的操作中使用这个上下文。

如下是实现ApplicationContextAware接口的类的代码案例,如下:

@Component  
public class MyApplicationContextAware implements ApplicationContextAware {  private ApplicationContext applicationContext;  @Override  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {  this.applicationContext = applicationContext;  }  public ApplicationContext getApplicationContext() {  return this.applicationContext;  }  
}

技术原理

ApplicationContextAware接口是Spring框架中用于让Bean感知到Spring应用上下文ApplicationContext的存在的一个标记接口。

当Spring容器创建一个实现了ApplicationContextAware接口的Bean时,它会自动调用该Bean的setApplicationContext方法,并将当前的ApplicationContext作为参数传入,这使得Bean能够访问到Spring容器的上下文,进而可以获取容器中的其他Bean、资源、配置信息等。

实现原理

  1. 标记接口: ApplicationContextAware接口本身并没有定义任何具体的业务逻辑,它只是一个标记接口,用于告诉Spring容器这个Bean需要特殊处理。
  2. 容器回调: 当Spring容器初始化一个Bean时,如果这个Bean实现了ApplicationContextAware接口,Spring容器会调用该Bean的setApplicationContext方法,并将当前的ApplicationContext对象作为参数传入。
  3. 内部状态保存: 实现ApplicationContextAware接口的Bean通常会在其内部保存这个传入的ApplicationContext引用,以便后续使用。
  4. 使用上下文: 一旦Bean保存了ApplicationContext的引用,它就可以使用这个上下文来访问容器中的其他Bean,或者获取容器的其他服务。

工作机制

  1. Bean创建: 当Spring容器根据配置信息创建一个Bean实例时,它会检查这个Bean是否实现了任何Aware接口(包括ApplicationContextAware)。
  2. Aware接口处理: 如果Bean实现了Aware接口,Spring容器会调用相应的set*方法,注入相应的依赖,对于ApplicationContextAware,容器会调用setApplicationContext方法。
  3. 依赖注入: 在调用setApplicationContext方法时,Spring容器会将当前的ApplicationContext对象注入到Bean中,这个注入过程是通过Java反射机制实现的。
  4. Bean后处理: 在Bean的所有属性被设置之后,Spring容器会调用Bean的后处理器(如果配置了的话),进行额外的初始化工作,对于实现了InitializingBean接口的Bean,还会调用其afterPropertiesSet方法。
  5. 使用ApplicationContext: 一旦Bean被初始化并注入了ApplicationContext,它就可以使用这个上下文来执行各种操作,比如获取其他Bean、访问资源、读取配置等。

核心总结

Spring揭秘:ApplicationContextAware应用场景及实现原理! - 程序员古德

ApplicationContextAware接口允许开发者在Bean中轻松获取到应用上下文ApplicationContext,这使得Bean能够灵活地访问Spring容器中的其他Bean和资源,增强了组件间的解耦和可扩展性。

但是,过度使用ApplicationContextAware可能导致代码与Spring容器紧密耦合,降低了代码的可移植性和可测试性。

关注我,每天学习互联网编程技术 - 程序员古德

END!
END!
END!

往期回顾

精品文章

Spring揭秘:@import注解应用场景及实现原理!

Java并发基础:原子类之AtomicMarkableReference全面解析!

Java并发基础:concurrent Flow API全面解析

Java并发基础:CopyOnWriteArraySet全面解析

Java并发基础:ConcurrentSkipListMap全面解析

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

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

相关文章

双体系Java学习之关键字,标识符以及命名规范

刚开学&#xff0c;然后之前的课程暂时停在了多态&#xff0c;接下来开始跟着学校的步伐重新开始学一下&#xff0c;谢谢&#xff01;&#xff01;&#xff01; 关键字 标识符 命名规范

响应式编程五股票订阅系统实现

响应式编程五 使用StepVerifier测试响应式流StepVerifier要点 使用StepVerifier进行高级测试股票订阅系统数据库表 使用StepVerifier测试响应式流 出于测试目的&#xff0c;Reactor 提供了额外的 reactor-test 模块&#xff0c;该模块提供了 StepVerifier。StepVerifier 提供了…

Android视角看鸿蒙第三课(module.json中的各字段含义之nametype)

Android视角看鸿蒙第三课(module.json中的各字段含义) 前言 上篇文章我们试图找到鸿蒙app的程序入口&#xff0c;确定了在鸿蒙工程中,由AppScope下的app.json5负责应用程序的图标及名称,由entry->src->main-module.json5负责桌面图标及名称的展示。 AppScope下的app.js…

YOLOv8实例分割实战:ONNX模型转换及TensorRT部署

课程链接&#xff1a;https://edu.csdn.net/course/detail/39320 PyTorch版的YOLOv8支持高性能的实时实例分割。 TensorRT是针对英伟达GPU的加速工具。 ONNX &#xff08;Open Neural Network Exchange&#xff09; 作为一个开放的网络模型中间表示&#xff08;IR&#xff0…

2024年最新阿里云服务器地域选择方法,以及可用区说明

阿里云服务器地域和可用区怎么选择&#xff1f;地域是指云服务器所在物理数据中心的位置&#xff0c;地域选择就近选择&#xff0c;访客距离地域所在城市越近网络延迟越低&#xff0c;速度就越快&#xff1b;可用区是指同一个地域下&#xff0c;网络和电力相互独立的区域&#…

linux命令行或桌面 显卡压力测试

windows下的压力测试非常简单&#xff0c;有很多图形化的测试工具 在github上找到一个项目&#xff1a;github链接 1.下载工具 cd /usr/localgit clone https://github.com/wilicc/gpu-burn如果没有安装git&#xff0c;则先安装 apt-get install git2.安装 cd /usr/local/…

SpringBoot源码解读与原理分析(三)条件装配

文章目录 2.3 Spring Framework的条件装配2.3.1 基于Profile的装配1.Profile源码解读2.使用Profile注解&#xff08;3&#xff09;命令行参数配置Profile3.Profile运用于实际开发4.Profile的不足 2.3.2 基于Conditional的装配1.Conditional源码解读2.Conditional使用3.Conditio…

[pdf]《软件方法》强化自测题业务建模需求分析共191页,230题

潘加宇《软件方法》强化自测题业务建模需求分析共191页&#xff0c;230题&#xff0c;已上传CSDN资源。 在完成书中自测题基础上&#xff0c;进一步强化。 也可到以下地址下载&#xff1a; 资料http://www.umlchina.com/url/quizad.html 如果需要网盘提取码&#xff1a;uml…

北斗卫星助力无人机在沙漠播种,促进沙漠治理

北斗卫星助力无人机在沙漠播种&#xff0c;促进沙漠治理 近年来&#xff0c;随着科技的不断发展&#xff0c;北斗卫星和无人机技术的结合被广泛应用于沙漠治理领域&#xff0c;为解决沙漠化问题提供了全新的思路和解决方案。 近日&#xff0c;黄河“几字弯”北岸的内蒙古自治…

FreeRTOS操作系统学习——空闲任务及其钩子函数

空闲任务 当 FreeRTOS 的调度器启动以后就会自动的创建一个空闲任务&#xff0c;这样就可以确保至少有一任务可以运行。但是这个空闲任务使用最低优先级&#xff0c;如果应用中有其他高优先级任务处于就绪态的话这个空闲任务就不会跟高优先级的任务抢占 CPU 资源。空闲任务还有…

mirthConnect忽略HTTPS SSL验证

mirthConnect SSL忽略验证 1、下载https网站证书 点击不安全---->证书无效 2、查看mirth 秘钥库口令 在mirthConnect 的conf目录下面keystore.storepass 3、导入证书到本地 在jdk的bin目录下面执行 keytool -importcert -file "下载的网站证书路径" -keysto…

经典语义分割(二)医学图像分割模型UNet

经典语义分割(二)医学图像分割模型UNet 我们之前介绍了全卷积神经网络( FCN) &#xff0c;FCN是基于深度学习的语义分割算法的开山之作。 今天我们介绍另一个语义分割的经典模型—UNet&#xff0c;它兼具轻量化与高性能&#xff0c;通常作为语义分割任务的基线测试模型&#x…

Springboot 的几种配置文件形式

方式一&#xff1a;多个yml文件 步骤1&#xff1a;创建多个配置文件 application.yml #主配置文件 application-dev.yml #开发环境的配置 application-prod.yml #生产环境的配置 application-test.yml #测试环境的配置步骤2&#xff1a;applicaiton.yml中指定配置 在a…

时光机关:探秘Java中的Timer和TimerTask

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 时光机关&#xff1a;探秘Java中的Timer和TimerTask 前言Timer和TimerTask的基本概念Timer&#xff1a;TimerTask&#xff1a;为何它们是 Java 中任务调度的得力工具&#xff1a; Timer的使用方法创建…

2024【问题解决】Github 2024无法克隆git clone自从签了2F2安全协议之后

项目场景:ping通Github但没法clone–502 问题描述 提示:ping通Github但没法clone--502: 例如:git clone https://gitclone.com/l.git/*** $ git clone https://github.com/darrenpig/Yocto Cloning into Yocto_tutorial... fatal: unable to access https://gitclone.co…

Yii2中如何使用scenario场景,使rules按不同运用进行字段验证

Yii2中如何使用scenario场景&#xff0c;使rules按不同运用进行字段验证 当创建news新闻form表单时&#xff1a; 添加新闻的时候执行create动作。 必填字段&#xff1a;title-标题&#xff0c;picture-图片&#xff0c;description-描述。 这时候在model里News.php下rules规则…

web3时事粥报

比特币正成为更具有吸引力的通胀对冲工具 在通胀的宏观经济浪潮中&#xff0c;比特币正逐渐崭露头角&#xff0c;成为那些渴望多元化投资组合的投资者眼中的璀璨明星。Kooner 预测&#xff0c;2024年&#xff0c;各种宏观经济挑战可能进一步提升比特币、黄金和白银等资产的避险…

shell脚本一键部署docker

Docker介绍 Docker 是一个开源的平台&#xff0c;用于开发、交付和运行应用程序。它利用容器化技术&#xff0c;可以帮助开发人员更轻松地打包应用程序及其依赖项&#xff0c;并将其部署到任何环境中&#xff0c;无论是开发工作站、数据中心还是云中。以下是 Docker 的一些关键…

python中的文件操作2

文件遍历 在Python中&#xff0c;遍历文件通常指的是逐行读取文件中的内容。这种方式对于处理大型文件特别有用&#xff0c;因为它不需要一次性将整个文件加载到内存中。下面是几种常见的遍历文件内容的方法&#xff1a; 1. 使用with语句和for循环 这是最推荐的方式&#xf…

两天学会微服务网关Gateway-Gateway工作原理

锋哥原创的微服务网关Gateway视频教程&#xff1a; Gateway微服务网关视频教程&#xff08;无废话版&#xff09;_哔哩哔哩_bilibiliGateway微服务网关视频教程&#xff08;无废话版&#xff09;共计17条视频&#xff0c;包括&#xff1a;1_Gateway简介、2_Gateway工作原理、3…