Spring IOC 之深入分析 Aware 接口

 🎬作者简介:大家好,我是小徐🥇
☁️博客首页:CSDN主页小徐的博客
🌄每日一句:好学而不勤非真好学者

📜 欢迎大家关注! ❤️

AbstractAutowireCapableBeanFactory 的 #doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) 方法,主要干三件事情:

  1. 实例化 bean 对象:#createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) 方法。
  2. 属性注入:#populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) 方法。
  3. 初始化 bean 对象:#initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) 方法。

而初始化 bean 对象时,也是干了三件事情:

  1. 激活 Aware 方法
  2. 后置处理器的应用
  3. 激活自定义的 init 方法

这篇主要分析 Aware 接口。

1. Aware 接口

org.springframework.beans.factory.Aware 接口,定义如下:

/**
 * Marker superinterface indicating that a bean is eligible to be
 * notified by the Spring container of a particular framework object
 * through a callback-style method. Actual method signature is
 * determined by individual subinterfaces, but should typically
 * consist of just one void-returning method that accepts a single
 * argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default
 * functionality. Rather, processing must be done explicitly, for example
 * in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
 * for examples of processing {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @since 3.1
 */
public interface Aware {

}

Aware 接口为 Spring 容器的核心接口,是一个具有标识作用的超级接口,实现了该接口的 bean 是具有被 Spring 容器通知的能力,通知的方式是采用回调的方式。

Aware 接口是一个空接口,实际的方法签名由各个子接口来确定,且该接口通常只会有一个接收单参数的 set 方法,该 set 方法的命名方式为 set + 去掉接口名中的 Aware 后缀,即 XxxAware 接口,则方法定义为 setXxx(),例如 BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。

Aware 的子接口需要提供一个 setXxx 方法,我们知道 set 是设置属性值的方法,即 Aware 类接口的 setXxx 方法其实就是设置 xxx 属性值的。 Aware 的含义是感知的、感应的,那么在 Spring 容器中是如何实现感知并设置属性值得呢?我们可以从初始化 bean 中的激活 Aware 的方法 #invokeAwareMethods(final String beanName, final Object bean) 中看到一点点,代码如下:

// AbstractAutowireCapableBeanFactory.java

private void invokeAwareMethods(final String beanName, final Object bean) {
	if (bean instanceof Aware) {
	    // BeanNameAware
		if (bean instanceof BeanNameAware) {
			((BeanNameAware) bean).setBeanName(beanName);
		}
		// BeanClassLoaderAware
		if (bean instanceof BeanClassLoaderAware) {
			ClassLoader bcl = getBeanClassLoader();
			if (bcl != null) {
				((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
			}
		}
		// BeanFactoryAware
		if (bean instanceof BeanFactoryAware) {
			((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
		}
	}
}
  • 首先,判断 bean 实例是否属于 Aware 接口的范畴,如果是的话,则调用实例的 setXxx() 方法给实例设置 xxx 属性值,在 #invokeAwareMethods(...) 方法,主要是设置 beanName,beanClassLoader、BeanFactory 中三个属性值。

2. Aware 子类

Spring 提供了一系列的 Aware 接口,如下图(部分):上面只是一部分子类,从这里我们可以看到 Spring 提供的 Aware 接口是是何其多。同时从上图我们也看到了几个比较熟悉的接口,如 BeanClassLoaderAware、BeanFactoryAware、BeanNameAware,下面就这三个接口来做一个简单的演示,先看各自的定义:

public interface BeanClassLoaderAware extends Aware {

    /**
    * 将 BeanClassLoader 提供给 bean 实例回调
    * 在 bean 属性填充之后、初始化回调之前回调,
    * 例如InitializingBean的InitializingBean.afterPropertiesSet()方法或自定义init方法
    */
    void setBeanClassLoader(ClassLoader classLoader);

}


public interface BeanFactoryAware extends Aware {
    /**
    * 将 BeanFactory 提供给 bean 实例回调
    * 调用时机和 setBeanClassLoader 一样
    */
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;

}


public interface BeanNameAware extends Aware {

    /**
    * 在创建此 bean 的 bean工厂中设置 beanName
    */
    void setBeanName(String name);

}


public interface ApplicationContextAware extends Aware {

    /**
     * 设置此 bean 对象的 ApplicationContext,通常,该方法用于初始化对象
     */
    void setApplicationContext(ApplicationContext applicationContext)
        throws BeansException;

}

2.1 示例

下面简单演示下上面四个接口的使用方法:

public class MyApplicationAware implements BeanNameAware,BeanFactoryAware,BeanClassLoaderAware,ApplicationContextAware{

    private String beanName;

    private BeanFactory beanFactory;

    private ClassLoader classLoader;

    private ApplicationContext applicationContext;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("调用了 BeanClassLoaderAware 的 setBeanClassLoader 方法");
        this.classLoader = classLoader;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("调用了 BeanFactoryAware 的 setBeanFactory 方法");
        this.beanFactory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("调用了 BeanNameAware 的 setBeanName 方法");
        this.beanName = name;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("调用了 ApplicationContextAware 的 setApplicationContext 方法");
        this.applicationContext = applicationContext;
    }

    public void display(){
        System.out.println("beanName:" + beanName);
        System.out.println("是否为单例:" + beanFactory.isSingleton(beanName));
        System.out.println("系统环境为:" + applicationContext.getEnvironment());
    }
}

测试方法如下:

public static void main(String[] args) {
    ClassPathResource resource = new ClassPathResource("spring.xml");
    DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
    reader.loadBeanDefinitions(resource);

    MyApplicationAware applicationAware = (MyApplicationAware) factory.getBean("myApplicationAware");
    applicationAware.display();
}

运行结果:从该运行结果可以看出,这里只执行了三个 Aware 接口的 set 方法,原因就是通过 #getBean(...) 方法调用时,在激活 Aware 接口时只检测了 BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 三个 Aware 接口。如果将测试方法调整为下面:

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    MyApplicationAware applicationAware = (MyApplicationAware) applicationContext.getBean("myApplicationAware");
    applicationAware.display();
}

则运行结果如下:

3. 总结

从本文我们基本上就可以 Aware 真正的含义是什么了?感知,其实是 Spring 容器在初始化主动检测当前 bean 是否实现了 Aware 接口,如果实现了则回调其 set 方法将相应的参数设置给该 bean ,这个时候该 bean 就从 Spring 容器中取得相应的资源。

最后文章末尾列出部分常用的 Aware 子接口,便于日后查询:

  • LoadTimeWeaverAware:加载Spring Bean时织入第三方模块,如AspectJ
  • BeanClassLoaderAware:加载Spring Bean的类加载器
  • BootstrapContextAware:资源适配器BootstrapContext,如JCA,CCI
  • ResourceLoaderAware:底层访问资源的加载器
  • BeanFactoryAware:声明BeanFactory
  • PortletConfigAware:PortletConfig
  • PortletContextAware:PortletContext
  • ServletConfigAware:ServletConfig
  • ServletContextAware:ServletContext
  • MessageSourceAware:国际化
  • ApplicationEventPublisherAware:应用事件
  • NotificationPublisherAware:JMX通知
  • BeanNameAware:声明Spring Bean的名字

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

小程序中封装下拉选择框

小程序中没有现成的下拉选择组件&#xff0c;有个picker组件&#xff0c;但是是底部弹出的&#xff0c;不满足我的需求&#xff0c;所以重新封装了一个。 封装的下拉组件 html部分&#xff1a; <view class"select_all_view"><!-- 内容说明&#xff0c;可…

设计一个可以智能训练神经网络的流程

设计一个可以智能训练神经网络的流程,需要考虑以下几个关键步骤: 初始化参数:设定初始的batch size和learning rate,以及其他的神经网络参数。训练循环:开始训练过程,每次迭代更新网络的权重。监控loss:在每个训练周期(epoch)后,监控loss的变化情况。动态调整:根据l…

python 多线程编程(一)

文章目录 threading - 基于线程的并行线程对象thread 类thread方法thread 属性例子 锁对象递归锁对象 条件对象 队列Queue对象SimpleQueque 对象例子 最近的工作需要用到多线程提升程序的运行效率&#xff0c;以前一直没有机会进行多线程编程&#xff0c;所以一直没有机会学习p…

Intellij IDEA各种调试+开发中常见bug

Intellij IDEA中使用好Debug&#xff0c;主要包括如下内容&#xff1a; 一、Debug开篇 ①、以Debug模式启动服务&#xff0c;左边的一个按钮则是以Run模式启动。在开发中&#xff0c;我一般会直接启动Debug模式&#xff0c;方便随时调试代码。 ②、断点&#xff1a;在左边行…

docker更换镜像源

添加的镜像源 {"registry-mirrors": ["https://registry.cn-hangzhou.aliyuncs.com", "https://reg-mirror.qiniu.com/", "https://docker.mirrors.ustc.edu.cn"] }docker更换镜像源之后一定要重启守卫 systemctl daemon-reloaddock…

虚幻5源码版打包服务端

适用情况&#xff0c;windows系统&#xff0c;已经安装vs2022之类的&#xff0c;和UE5适配的版本 源码版使用 1.下载源码版&#xff0c;推荐下载 压缩包 tar.gz那个&#xff0c;zip和git clone我老是下载不下载来&#xff0c;只是这个压缩包要解压1个多小时… 2.点击 源码的…

在线JSON转SQL工具

在线JSON转SQL - BTool在线工具软件&#xff0c;为开发者提供方便。在线JSON转SQL工具可以将JSON文件中的数据或者JSON对象转换为SQL插入语句&#xff0c;方便用户将数据导入到数据库中。用户可以通过简单的界面上传JSON文件&#xff0c;或者文本框输入&#xff0c;点击JSON转S…

Docker进阶篇-compose容器编排

一、描述 Docker-Compose是Docker官方的开源项目&#xff0c;负责实现对Docker容器集群的快速编排。 Compose是Docker公司推出的一个工具软件&#xff0c;可以管理多个Docker容器组成一个应用。需要定义 一个YAML格式的配置文件docker-compose.yml&#xff0c;配置好多个容器…

OpenResty 安装

安装OpenResty 1.安装 首先你的Linux虚拟机必须联网 1&#xff09;安装开发库 首先要安装OpenResty的依赖开发库&#xff0c;执行命令&#xff1a; yum install -y pcre-devel openssl-devel gcc --skip-broken2&#xff09;安装OpenResty仓库 你可以在你的 CentOS 系统中…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(六)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十四章&#xff1a;使用卷积神经网络进行深度计算机视觉 尽管 IBM 的 Deep Blue 超级计算机在 1996 年击败了国际象棋世界冠军…

MMLAB的实例分割算法mmsegmentation

当谈及实例分割时&#xff0c;人们往往只会提到一些早期的经典算法&#xff0c;比如 PSP-Net、DeepLabv3、DeepLabv3 和 U-Net。然而&#xff0c;实例分割领域已经在过去的五六年中蓬勃发展&#xff0c;涌现出许多新的算法。今天&#xff0c;让我们一起探索这个算法库&#xff…

mysql批量修改数据表的排序规则

1. 根据条件修改下边的sql 将其修改成你需要修改的规则以及对应的数据库名&#xff0c;并执行。 SELECT CONCAT(ALTER TABLE , TABLE_SCHEMA, ., TABLE_NAME, CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;) 查询结果 from information_schema.tables where…

使用 LoRA 在 vi​​ggo 数据集上微调 Microsoft phi-2 小语言模型

一、说明 Microsoft 的基于 Transformer 的小语言模型。它可以根据 MIT 许可在HuggingFace上使用。 它在 96 个 A100 GPU 上使用 1.4T 令牌进行了 14 天的训练。Phi-2 是一个 27 亿个参数的预训练 Transformer&#xff0c;不使用 RLHF 或指示微调。它进行下一个标记预测&#x…

算法笔记刷题日记——3.简单入门模拟 3.1简单模拟

刷题日记 3.1 简单模拟 此类题型根据题目描述进行代码的编写&#xff0c;考察代码能力&#xff0c;刷题记录如下&#xff1a; B1001 B1032 B1016 B1026 B1046 B1008 B1012 B1018 A1042 A1046 A1065 B1010 A1002 A1009 错题记录 B1008 数组元素循环右移问题 一个数组_A_中存有…

Axios设置token到请求头的三种方式

1、为什么要携带token? 用户登录时&#xff0c;后端会返回一个token&#xff0c;并且保存到浏览器的localstorage中&#xff0c;可以根据localstorage中的token判断用户是否登录&#xff0c;登录后才有权限访问相关的页面&#xff0c;所以当发送请求时&#xff0c;都要携带to…

ARM PAC指针认证的侧信道攻击——PACMAN安全漏洞

目录 Q1. PACMAN论文的内容是什么&#xff1f; Q2. Arm处理器是否存在漏洞&#xff1f; Q3. 受Arm合作伙伴架构许可设计的处理器实现是否受到影响&#xff1f; Q4. Cortex-M85受到影响吗&#xff1f; Q5. Cortex-R82受到影响吗&#xff1f; Q6. 指针认证如何保护软件&…

VC++添加菜单学习

新建一个单文档工程&#xff1b; 完成以后看一下有没有出现如下图的 资源视图 的tab&#xff1b;如果没有&#xff0c;在文件列表中找到xxx.rc2文件&#xff1b; 点击 资源视图 的tab&#xff0c;或者双击 .rc2 文件名&#xff0c;就会转到如下图的资源视图&#xff1b;然后展…

AI助力农作物自动采摘,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建作物生产场景下番茄采摘检测计数分析系统

去年十一那会无意间刷到一个视频展示的就是德国机械收割机非常高效自动化地24小时不间断地在超广阔的土地上采摘各种作物&#xff0c;专家设计出来了很多用于采摘不同农作物的大型机械&#xff0c;看着非常震撼&#xff0c;但是我们国内农业的发展还是相对比较滞后的&#xff0…

MySQL 架构和性能优化

重点&#xff1a; 视图&#xff0c;函数&#xff0c;存储过程&#xff0c;触发器&#xff0c;事件&#xff08; 了解 &#xff09; 用户管理&#xff0c;密码管理 grant revoke 权限管理 MySQL 架构&#xff08; 了解 &#xff09; 存储引擎&#xff1a;MyISAM 和 InnoDB …

黑豹程序员-ElementPlus支持树型组件带图标以及icon避坑

效果 vue代码 参数说明&#xff1a;node当前节点&#xff0c;data当前节点后台传入数据。 el-tree自身不支持图标&#xff0c;需要自己去利于实现&#xff0c;并有个坑&#xff0c;和elementui写法不同。 <el-col :span"12"><el-form-item label"绑定…