Spring Aware介绍

读完这篇文章你将会收获到
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 接口。然后我们在 Person 和 CatFactory 中实现了接口 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 流程的文章可以知道。这里就不重复了
其他
至于 BeanClassLoaderAware 和 BeanFactoryAware 就不演示代码了、挺简单的使用。

Spring 里面比较常见的 Aware 接口
我们看到很多像 ApplicationContextAware 或者 EnvironmentAware 的 Aware 接口、并没有在 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介绍的更多相关文章
- Spring Batch 中文参考文档 V3.0.6 - 1 Spring Batch介绍
1 Spring Batch介绍 企业领域中许多应用系统需要采用批处理的方式在特定环境中运行业务操作任务.这种业务作业包括自动化,大量信息的复杂操作,他们不需要人工干预,并能高效运行.这些典型作业包括 ...
- [翻译]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 ...
- Spring知识点回顾(08)spring aware
Spring知识点回顾(08)spring aware BeanNameAware 获得容器中的bean名称 BeanFactoryAware 获得当前的bean factory Applicatio ...
- Spring Boot实战笔记(五)-- Spring高级话题(Spring Aware)
一.Spring Aware Spring 依赖注入的最大亮点就是你所有的 Bean 对 Spring容器的存在是没有意识的.即你可以将你的容器替换成其他的容器,如Google Guice,这时 Be ...
- Spring 的介绍和目标
1. Spring介绍 打开Spring 官网查看对 Spring 的介绍和目标 http://www.springsource.org/about We believe that: · J2EE s ...
- Spring的介绍与搭建
一.Spring的介绍 二.Spring的搭建 (1)导包 (2)创建一个对象 (3)书写配置注册对象到容器 (4)代码测试
- Spring Shell介绍
最近开发中在下遇到了spring-shell开发工具的项目,现在整理了相关文章,以供大家学习 本博客相关的文章均是在Spring Shell 1.2.0的基础上建立 Spring Shell介绍 ...
- Spring DevTools 介绍
Spring DevTools 介绍 Spring Boot包括一组额外的工具,可以使应用程序开发体验更加愉快. spring-boot-devtools模块可以包含在任何项目中,它可以节省大量的时间 ...
- Spring Aware容器感知技术
Spring Aware是什么 Spring提供Aware接口能让Bean感知Spring容器的存在,即让Bean可以使用Spring容器所提供的资源. Spring Aware的分类 几种常用的Aw ...
随机推荐
- Java实现 蓝桥杯VIP 算法训练 JAM计数法
题目描述 Jam是个喜欢标新立异的科学怪人.他不使用阿拉伯数字计数,而是使用小 写英文字母计数,他觉得这样做,会使世界更加丰富多彩.在他的计数法中,每个数字的位数都是相同的(使用相同个数的字母),英文 ...
- Java实现 蓝桥杯VIP 算法训练 确定元音字母位置
算法训练 确定元音字母位置 时间限制:1.0s 内存限制:512.0MB 输入一个字符串,编写程序输出该字符串中元音字母的首次出现位置,如果没有元音字母输出0.英语元音字母只有'a'.'e'.'i'. ...
- Java实现 LeetCode 137 只出现一次的数字
public static int singleNumber(int[] nums) { int res = 0; for(int i=0;i<nums.length;i++) res ^= n ...
- Java实现中值问题
中值问题是求一个n个数列表中某一数组下标k,它要求该下标元素比列表中的一半元素大,又比另一半元素小,这个中间的值被称为中值. 使用Lomuto划分算法思想,此处引用<算法设计与分析基础>第 ...
- iOS -程序启动原理和UIApplication的介绍
一.UIApplication 简介 (1)UIApplication对象是应用程序的象征,一个UIApplication对象就代表一个应用程序. (2)每一个Application都有自 ...
- jenkins 添加用户管理权限
一.前言 小组开会通知 想把jenkins 构建的权限给开发,这样的话效率会增加.运维也不必每次帮助开发去构建发布. 1.规划 jenkins 四个项目分别对应三个人负责.项目下的只负责 CI.UAT ...
- 遇到Error:Execution failed for task ':app:transformClassesWithDexForDebug'的解决方案
原因:项目中包含了所有的google play service 解决:只需要使用必要的服务即可 将compile 'com.google.android.gms:play-services:8.1.0 ...
- mysql导入超大sql文件
mysql导入超大sql文件 在网上找了个2017年行政区划的sql文件,需要导入到本地mysql库中,同事使用navicat导入的时候直接卡死了,该SQL文件差不多112MB大小.通过百度.goog ...
- jstl中<c:if>标签属性用法
今天用jstl+el从session域中获取属性,遇到了问题 org.apache.jasper.JasperException: <h3>Validation error message ...
- 02 . Zabbix配置监控项及聚合图形
安装Zabbix Agent监控本机 安装agent软件 与server端不同,Agent只需安装zabbix-agent包 cat /etc/yum.repos.d/zabbix.repo [zab ...