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

  • 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 第十一届 蓝桥杯 省模拟赛 19000互质的个数

    问题描述 不超过19000的正整数中,与19000互质的数的个数是多少? 答案提交 这是一道结果填空的题,你只需要算出结果后提交即可.本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将 ...

  2. Java实现 洛谷 P1064 金明的预算方案

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过NN元 ...

  3. Java实现蓝桥杯 算法训练 大等于n的最小完全平方数

    试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...

  4. requireJS模块化

    1. JavaScript里面js代码的写法:目标是解决冲突和依赖 函数式编程,全局函数和变量--很容易覆盖 对象的写法--也会从外面改变 命名空间:利用名称不同缓冲js代码的冲突---名称太长,不方 ...

  5. 深入浅出-iOS Block原理和内存中位置

    Posted by 微博@Yangsc_o 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0 #简介 今天回顾一下blcok,基本 ...

  6. Android开发之修改Manifest中meta-data的数据

    代码 private void initFMMap() { ApplicationInfo appInfo = null; try { appInfo = this.getPackageManager ...

  7. Markdown 主题修改

    加粗字体的颜色修改 strong, b{ color: #111111; } 斜体的颜色修改 em, i { color: #111111; } 高亮字体的背景颜色修改 #write mark { b ...

  8. 匿名实现类&匿名对象

    学习过程中经常搞不清匿名类&匿名对象怎么用,今天就把常用的方式总结一遍. 1.创建了非匿名实现类的非匿名对象 //定义USB接口 interface USB{ void inputInofo( ...

  9. asp.net Mvc 路由详解,非常详细.

    关于路由的理解 为什么要定义路由?路由的定义在开发中的工作量非常小,但是非常重要,因为任何请求都离不开路由. 各个电商网站的 URL 使用非常灵活,都离不开路由的定义,请大家参考几家电商的 URL 如 ...

  10. postman获得时间戳和md5加密的方法

    注意点:记得用postman.setGlobalVariable设置全局变量,不然{{strmd5}}这种变量取不到值