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

  • 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 547 朋友圈(并查集?)

    547. 朋友圈 班上有 N 名学生.其中有些人是朋友,有些则不是.他们的友谊具有是传递性.如果已知 A 是 B 的朋友,B 是 C 的朋友,那么我们可以认为 A 也是 C 的朋友.所谓的朋友圈,是指 ...

  2. Java实现 洛谷 P1328 生活大爆炸版石头剪刀布

    import java.util.Scanner; public class Main{ private static int[] duel(int playerA, int playerB){ in ...

  3. java实现立方和等式

    考虑方程式:a^3 + b^3 = c^3 + d^3 其中:"^"表示乘方.a.b.c.d是互不相同的小于30的正整数. 这个方程有很多解.比如: a = 1,b=12,c=9, ...

  4. Java实现第九届蓝桥杯猴子分香蕉

    猴子分香蕉 题目描述 5只猴子是好朋友,在海边的椰子树上睡着了.这期间,有商船把一大堆香蕉忘记在沙滩上离去. 第1只猴子醒来,把香蕉均分成5堆,还剩下1个,就吃掉并把自己的一份藏起来继续睡觉. 第2只 ...

  5. java实现第七届蓝桥杯取球博弈

    题目9.取球博弈 取球博弈 两个人玩取球的游戏. 一共有N个球,每人轮流取球,每次可取集合{n1,n2,n3}中的任何一个数目. 如果无法继续取球,则游戏结束. 此时,持有奇数个球的一方获胜. 如果两 ...

  6. 团体天梯赛L1-041.寻找250

    对方不想和你说话,并向你扔了一串数…… 而你必须从这一串数字中找到“250”这个高大上的感人数字. 输入格式: 输入在一行中给出不知道多少个绝对值不超过1000的整数,其中保证至少存在一个“250”. ...

  7. IOS App如何调用python后端服务

    本篇文章旨在通过一个小的Demo形式来了解ios app是如何调用python后端服务的,以便我们在今后的工作中可以清晰的明白ios app与后端服务之间是如何实现交互的,今天的示例是拿登录功能做一个 ...

  8. 2 个步骤为 VSCode 配置工程头文件路径!

    我用 VSCode 来 Coding,这个编辑器需要自己配置头文件路径,就是自动建立一个 c_cpp_properties.json 文件来管理头文件路径,然后需要用哪些库就手动加上即可,方法很简单, ...

  9. 玩转华为物联网IoTDA服务系列三-自动售货机销售分析场景示例

    场景简介 通过收集自动售货机系统的销售数据,EI数据分析售货销量状况. 该场景主要描述的是设备可以通过MQTT协议与物联网平台进行交互,应用侧可以到物联网平台订阅设备侧变化的通知,用户可以在控制台或通 ...

  10. 【JMeter_16】JMeter逻辑控制器__随机控制器<Random Controller>

    随机控制器<Random Controller> 业务逻辑: 当每次执行到该逻辑控制器时,随机挑选控制器下的任意一个子节点<取样器.逻辑控制器> Ignore sub-cont ...