读完这篇文章你将会收获到

  • Aware 的使用和介绍
  • BeanFactoryAware 的触发时机
  • ApplicationContextAware 的触发时机以及它通过扩展 BeanPostProcessor 来实现

我们在 getBean 流程中曾经谈到过 Spring 回调 Aware 接口

	private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}

我们今天就来聊一下 Aware 接口

public interface Aware {

}

一个空的接口、啥都没有、看注释说它只是一个标志性的接口、实现该接口的 bean 会被 Spring 以回调的方式进行通知、告诉你某个阶段某件事情发生了

BeanNameAware

public interface BeanNameAware extends Aware {
void setBeanName(String name);
}

这个我们举两个有意思的例子,一个是内部 bean 、一个是 factoryBean

<bean id="customer" class="com.demo.aware.Customer">
<constructor-arg name="person">
<bean class="com.demo.aware.Person">
<property name="name" value="coderLi"/>
<property name="address" value="china"/>
<property name="age" value="666"/>
</bean>
</constructor-arg>
</bean> <bean id="cat" class="com.demo.aware.CatFactory"/>

具体的类就不贴了、没啥逻辑、CatFactory 就实现了 Spring 提供的 FactoryBean 接口。然后我们在 PersonCatFactory 中实现了接口 BeanNameAware 、并打印其参数 name

Resource resource = new ClassPathResource("aware/coderLi.xml");
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
defaultListableBeanFactory.getBean("customer");
defaultListableBeanFactory.getBean("cat");

打印的结果就是:

bean Name aware [bean Name is] :com.demo.aware.Person#71a794e5
bean Name aware [bean Name is] :cat

我们打断点在它们 getBean 之后,针对下面图片的结果你是否有疑惑呢

第一个是内部 bean Person 对象不在 Spring 的容器中、但是它却触发了 Aware 接口的回调 , 第二个是第一级缓存和 beanFactory 缓存中 key 都是 cat

第一个问题其实很简单、主要是构建 Customer 的构造函数的参数 Person 的时候、在 BeanDefinitionValueResolver#resolveInnerBean 中直接调用了 createBean 方法、然后就到了 doCreateBean 、之后就回调 Aware 接口、但是没用放到 Spring 容器中

第二个问题、其实两者的 key 一样是完全没有问题的、往前翻我分析 getBean 流程的文章可以知道。这里就不重复了

其他

至于 BeanClassLoaderAwareBeanFactoryAware 就不演示代码了、挺简单的使用。

Spring 里面比较常见的 Aware 接口

我们看到很多像 ApplicationContextAware 或者 EnvironmentAwareAware 接口、并没有在 invokeAwareMethods 中被调用到、因为其实这些都是在使用 ApplicationContext 的时候才会被触发的、具体是在哪里被触发调用呢?

我们可以看到 ApplicationContextAwareProcessor#invokeAwareInterfaces

中就写了这么一段代码

private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}

ApplicationContextAwareProcessor 实现了 BeanPostProcessor 的、

那这样子的话就是在 doCreateBean 的时候、通过 initializeBean 进行回调了

那这个 ApplicationContextAwareProcessor 什么时候添加到 Spring 中啊

而这个方法则是在 refresh 方法中被调用了,而 refresh 的调用就不用介绍了把

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
} public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException { super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

其实 Spring 挺有意思的、将这个 ApplicationContextAwareProcessor 作为其第一个 BeanPostProcessor 接口、那么就能保证 Aware 接口被先回调、然后才到用户的 BeanPostProcessor 实现类

Spring Aware介绍的更多相关文章

  1. Spring Batch 中文参考文档 V3.0.6 - 1 Spring Batch介绍

    1 Spring Batch介绍 企业领域中许多应用系统需要采用批处理的方式在特定环境中运行业务操作任务.这种业务作业包括自动化,大量信息的复杂操作,他们不需要人工干预,并能高效运行.这些典型作业包括 ...

  2. [翻译]Spring框架参考文档(V4.3.3)-第二章Spring框架介绍 2.1 2.2 翻译--2.3待继续

    英文链接:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.ht ...

  3. Spring知识点回顾(08)spring aware

    Spring知识点回顾(08)spring aware BeanNameAware 获得容器中的bean名称 BeanFactoryAware 获得当前的bean factory Applicatio ...

  4. Spring Boot实战笔记(五)-- Spring高级话题(Spring Aware)

    一.Spring Aware Spring 依赖注入的最大亮点就是你所有的 Bean 对 Spring容器的存在是没有意识的.即你可以将你的容器替换成其他的容器,如Google Guice,这时 Be ...

  5. Spring 的介绍和目标

    1. Spring介绍 打开Spring 官网查看对 Spring 的介绍和目标 http://www.springsource.org/about We believe that: · J2EE s ...

  6. Spring的介绍与搭建

    一.Spring的介绍 二.Spring的搭建 (1)导包 (2)创建一个对象 (3)书写配置注册对象到容器 (4)代码测试

  7. Spring Shell介绍

    最近开发中在下遇到了spring-shell开发工具的项目,现在整理了相关文章,以供大家学习 本博客相关的文章均是在Spring Shell 1.2.0的基础上建立   Spring Shell介绍 ...

  8. Spring DevTools 介绍

    Spring DevTools 介绍 Spring Boot包括一组额外的工具,可以使应用程序开发体验更加愉快. spring-boot-devtools模块可以包含在任何项目中,它可以节省大量的时间 ...

  9. Spring Aware容器感知技术

    Spring Aware是什么 Spring提供Aware接口能让Bean感知Spring容器的存在,即让Bean可以使用Spring容器所提供的资源. Spring Aware的分类 几种常用的Aw ...

随机推荐

  1. Java实现 LeetCode 149 直线上最多的点数

    149. 直线上最多的点数 给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上. 示例 1: 输入: [[1,1],[2,2],[3,3]] 输出: 3 解释: ^ | | o | ...

  2. java实现欧拉与鸡蛋

    ** 欧拉与鸡蛋** 大数学家欧拉在集市上遇到了本村的两个农妇,每人跨着个空篮子.她们和欧拉打招呼说两人刚刚卖完了所有的鸡蛋. 欧拉随便问:"卖了多少鸡蛋呢?" 不料一个说:&qu ...

  3. python IDE pycharm的安装与使用

    Python开发最牛逼的IDE——pycharm (其实其它的工具,例如eclipse也可以写,只不过比较麻烦,需要安装很多的插件,所以说pycharm是最牛逼的) pycharm,下载专业版的,不要 ...

  4. TCP协议“三次握手”与“四次挥手”详解(下)

    前面进行“三次握手”建立连接后,当客户端的数据发送完毕,它就会要求与服务器端断开连接,那么就要进行“四次挥手”进行连接的释放. 注意,此处所谓的“客户端”与“服务器端”,只是为了方便标识连接的双方,即 ...

  5. Flutter 中 GestureDetector 的使用误区

    在实际开发中,我们通常需要实现某个组件的更多点击事件.比如:原生的RaisedButton组件是无法响应诸如拖拽或是按下.抬起等细化的动作,它只有一个onPressed()方法来表示.当我们想实现这些 ...

  6. VSCode最佳设置

    最近在学习Vue,用VSCode开发.经过摸索,VSCode最佳设置. { "eslint.enable": false, "workbench.colorTheme&q ...

  7. boost常用库(一):boost数值转换

    在STL中有一些字符转换函数,例如atoi,itoa等,在boost里面只需用一个函数lexical_cast进行转换,lexical_cast是模板方法,使用时需要传入类型.只能是数值类型转字符串. ...

  8. jenkins环境安装(windows)

    一.简介 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能.   二. Jenkins功能 1. ...

  9. 让LED程序在片外SDRAM中运行

    让LED程序在片外SDRAM中运行 一.引子 在前一篇文章中,我们已经成功点亮过LED了,为什么还要再重复一次呢? 我们已经知道,Mini2440开发板有两种启动模式:从NorFlash启动和从Nan ...

  10. [LOJ#500]「LibreOJ β Round」ZQC的拼图

    题目   点这里看题目. 分析   首先不难发现答案具有单调性,因此可以二分答案.答案上限为\(V=2m\times \max\{a_i, b_i\}\).   考虑如何去判断当前的答案.设这个答案为 ...