【死磕 Spring】----- IOC 之 深入分析 Aware 接口
doCreateBean() 方法主要干三件事情:
实例化 bean 对象: createBeanInstance()
属性注入: populateBean()
初始化 bean 对象: initializeBean()
而初始化 bean 对象时也是干了三件事情:
激活 Aware 方法
后置处理器的应用
激活自定义的 init 方法
接下来三篇文章将会详细分析这三件事情,这篇主要分析 Aware 接口。
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() 中看到一点点,如下:
首先判断 bean 实例是否属于 Aware 接口的范畴,如果是的话,则调用实例的 setXxx() 方法给实例设置 xxx 属性值,在 invokeAwareMethods() 方法主要是设置 beanName,beanClassLoader、BeanFactory 中三个属性值。
Spring 提供了一系列的 Aware 接口,如下图(部分):
上面只是一部分子类,从这里我们可以看到 Spring 提供的 Aware 接口是是何其多。同时从上图我们也看到了几个比较熟悉的接口,如 BeanClassLoaderAware、BeanFactoryAware、BeanNameAware,下面就这三个接口来做一个简单的演示,先看各自的定义:
public interface BeanClassLoaderAwareextendsAware{
/**
* 将 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;
}
下面简单演示下上面四个接口的使用方法:
public
class
MyApplicationAware
implements
BeanNameAware
,
BeanFactoryAware
,
BeanClassLoaderAware
,
ApplicationContextAware
{
private
String
beanName
;
private
BeanFactory
beanFactory
;
private
ClassLoader
classLoader
;
private
ApplicationContext
applicationContext
;
@Override
public
void
setBeanClassLoader
(
ClassLoader
classLoader
)
{
System
.
out
.
println
(
"调用了 BeanClassLoaderAware 的 setBeanClassLoader 方法"
);
this
.
classLoader
=
classLoader
;
}
@Override
public
void
setBeanFactory
(
BeanFactory
beanFactory
)
throws
BeansException
{
System
.
out
.
println
(
"调用了 BeanFactoryAware 的 setBeanFactory 方法"
);
this
.
beanFactory
=
beanFactory
;
}
@Override
public
void
setBeanName
(
String
name
)
{
System
.
out
.
println
(
"调用了 BeanNameAware 的 setBeanName 方法"
);
this
.
beanName
=
name
;
}
@Override
public
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
();
}
则运行结果如下:
从这了我们基本上就可以 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的名字
原文发布时间为:2018-12-24
本文作者:chenssy
本文来自云栖社区合作伙伴“ Java技术驿站”,了解相关信息可以关注“chenssy89”微信公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
深度好文 |Matplotlib 可视化最有价值的 50 个图表(附完整 Python 源代码)
在数据分析和可视化中最有用的 50 个 Matplotlib 图表。 这些图表列表允许您使用 python 的 matplotlib 和 seaborn 库选择要显示的可视化对象。 介绍这些图表根据可视化目标的7个不同情景进行分组。 例如,如果要想象两个变量之间的关系,请查看“关联”部分下的图表。 或者,如果您想要显示值如何随时间变化,请查看“变化”部分,依此类推。 有效图表的重要特征: 在不歪曲事实的情况下传达正确和必要的信息。 设计简单,您不必太费力就能理解它。 从审美角度支持信息而不是掩盖信息。 信息没有超负荷。 准备工作在代码运行前先引入下面的设置内容。 当然,单独的图表,可以重新设置显示要素。 # !pip install brewer2mpl import numpy as np import pandas as pd import matplotlib as mpl import matplotlib.pyplot as plt import seaborn as sns import warnings; warnings.filterwarnings(action='o...
-
下一篇
《快学 Go 语言》第 16 课 —— 包管理 GOPATH 和 Vendor
到目前位置我们一直在编写单文件代码,只有一个 main.go 文件。本节我们要开始朝完整的项目结构迈进,需要使用 Go 语言的模块管理功能来组织很多的代码文件。 细数 Go 语言的历史发展,模块管理经历了三个重要的阶段。第一阶段是通过全局的 GOPATH 来管理所有的第三方包,第二阶段是通过 Vendor 机制将项目的依赖包局部化,第三阶段是 Go 语言的最新功能 Go Module。 本节我们重点讲解前两个阶段,这两个阶段要求我们编写代码时必须在 GOPATH 下面对应的包路径目录里写。第三个阶段 Go Module 内容较新,也比较复杂需要另起一节单独讲解。 系统包路径Go 语言有很多内置包,内置包的使用需要用户手工 import 进来。Go 语言的内置包都是已经编译好的「包对象」,使用时编译器不需要进行二次编译。可以使用下面的命令查看这些已经编译好的包对象在哪里。该命令显示出来的后缀名为 .a 的文件就是已经编译好的包对象。 全局管理 GOPATHGo 语言的 GOPATH 路径下存放了全局的第三方依赖包,当我们在代码里面 import 某个第三方包时,编译器都会到 GOPATH...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2全家桶,快速入门学习开发网站教程
- MySQL数据库在高并发下的优化方案
- Red5直播服务器,属于Java语言的直播服务器