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.javaprivate void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {// BeanNameAwareif (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}// BeanClassLoaderAwareif (bean instanceof BeanClassLoaderAware) {ClassLoader bcl = getBeanClassLoader();if (bcl != null) {((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);}}// BeanFactoryAwareif (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;@Overridepublic void setBeanClassLoader(ClassLoader classLoader) {System.out.println("调用了 BeanClassLoaderAware 的 setBeanClassLoader 方法");this.classLoader = classLoader;}@Overridepublic void setBeanFactory(BeanFactory beanFactory) throws BeansException {System.out.println("调用了 BeanFactoryAware 的 setBeanFactory 方法");this.beanFactory = beanFactory;}@Overridepublic void setBeanName(String name) {System.out.println("调用了 BeanNameAware 的 setBeanName 方法");this.beanName = name;}@Overridepublic 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的名字

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

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

相关文章

vscode的ssh忽然连不上服务器:远程主机可能不符合glibc和libstdc++ VS Code服务器的先决条件

vscode自动更新了一下就发现连不上服务器了&#xff0c;我寻思估计一大堆人都寄了&#xff0c;一搜&#xff0c;果然哈哈哈哈 然后我直接搜一天内新发布的博客&#xff0c;还真给我搜到了这个问题&#xff0c;按照这个问题里面的回答&#xff08;vscode1.86无法远程连接waitin…

【C/C++ 17】继承

目录 一、继承的概念 二、基类和派生类对象赋值转换 三、继承的作用域 四、派生类的默认成员函数 五、继承与友元 六、继承与静态成员变量 七、菱形继承与虚拟继承 一、继承的概念 继承是指一个类可以通过继承获得另一个类的属性和方法&#xff0c;扩展自己的功能&…

通过Navicat for MySQL排查sql语句错误

开发的软件用到MySQL数据库&#xff0c;但在进行某个sql操作时执行失败了&#xff1a; 我们可以用Navicat for MySQL来排查sql语句是否存在语法错误等问题。将该sql语句复制 打开Navicat for MySQL&#xff0c;连接该软件所用到的MySQL数据库&#xff0c;点击“新建查询”。将刚…

HomeAssistant系统添加HACS插件商店与远程控制家中智能家居

文章目录 基本条件一、下载HACS源码二、添加HACS集成三、绑定米家设备 ​ 上文介绍了如何实现群晖Docker部署HomeAssistant&#xff0c;通过内网穿透在户外控制家庭中枢。本文将介绍如何安装HACS插件商店&#xff0c;将米家&#xff0c;果家设备接入 Home Assistant。 基本条件…

Java笔记 --- 六、IO流

六、IO流 概述 分类 纯文本文件&#xff1a;Windows自带的记事本打开能读懂的 eg&#xff1a;txt文件&#xff0c;md文件&#xff0c;xml文件&#xff0c;lrc文件 IO流体系 字节流 FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写到本地文件中…

vue3-内置组件-Transition

基于状态变化的过渡和动画&#xff08;常用&#xff09; 建议多看几遍~~。然后动手去写写&#xff0c;学编程只有多动手才能有感觉。 内置组件: 它在任意别的组件中都可以被使用&#xff0c;无需注册。 Vue 提供了两个内置组件&#xff0c;可以帮助你制作基于状态变化的过渡和动…

蓝桥杯省赛无忧 课件108 ST表

01 RMQ问题 02 ST表 03 区间最大值

Python程序设计 函数

简单函数 函数&#xff1a;就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。 函数的使用包含两个步骤&#xff1a; 定义函数 —— 封装 独立的功能 调用函数 —— 享受 封装 的成果 函数的作用&#xff0c;在开发程序时&#xff0c;使用…

C语言之数据在内存中的存储

目录 1. 整数在内存中的存储2. 大小端字节序和字节序判断什么是大小端&#xff1f;为什么有大小端&#xff1f;练习1练习2练习3练习4练习5练习6 3. 浮点数在内存中的存储浮点数存的过程浮点数取得过程练习题解析 1. 整数在内存中的存储 在讲解操作符的时候&#xff0c;我们已经…

图片解码显示

本文主要探讨基于s5pv210实现图片解码显示项目。 项目概述&#xff1a; 硬件&#xff1a;s5pv210&#xff08;已移植uboot,kernel,busybox,已搭建tftp,已挂在ntfs&#xff09; 软件:ubuntu14(已搭建tftp,搭建ntfs) 项目功能:基于s5pv210实现对bmp,jpeg,png三种图片的解析和显示…

RK3568平台 设备模型基本框架-kobject 和kset

一.什么是设备模型 字符设备驱动通常适用于相对简单的设备&#xff0c;对于一些更复杂的功能&#xff0c;比如说电源管理和热插拔事件管理&#xff0c;使用字符设备框架可能不够灵活和高效。为了应对更复杂的设备和功能&#xff0c;Linux内核提供了设备模型。设备模型允许开发…

C# 使用 MailKit 发送邮件(附demo)

C# 使用 MailKit 发送邮件&#xff08;附demo&#xff09; 介绍安装包&#xff08;依赖&#xff09;案例简单代码属性介绍&#xff1a;MailboxAddress属性介绍&#xff1a;BodyBuilderSMTP 服务器端口SSL的案例&#xff1a;非SSL&#xff1a; 介绍一下SMTP 介绍 MailKit 是一…