一、介绍
使用spring开发的同学,或多或少都使用过形如XxxAware这样的接口。spring文档中是这样解释Aware接口的:
Spring提供了广泛的Aware回调接口,让bean向容器表明它们需要某种基础设施依赖。
通常Aware有这样一个规则:Aware接口的名称,表示依赖对象的类名称。
例如,一个bean需要使用ApplicationContext,实现ApplicationContextAware接口即可。
二、使用demo
功能:我的一个bean想要使用ApplicationContext对象,来查看容器中有哪些bean
- 定义一个bean的类
如上规则,想要使用ApplicationContext对象,就要实现ApplicationContextAware接口
public class MyApplicationContextAware implements ApplicationContextAware {
// 用一个全局变量,保存接口回调时传入的applicationContext对象
private ApplicationContext applicationContext;
// 使用获取的applicationContext对象
public void printAllBean(){
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
System.out.println("当前容器中的bean如下:");
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
- 把MyApplicationContextAware这个bean注册到容器中
<bean id="myApplicationContextAware" class="com.kaka.spring.context.aware.MyApplicationContextAware"/>
- 执行代码
@Test
public void awareTest(){
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml");
MyApplicationContextAware myApplicationContextAware = classPathXmlApplicationContext.getBean("myApplicationContextAware", MyApplicationContextAware.class);
myApplicationContextAware.printAllBean();
}
- 执行结果
这个例子就是让bean实现一个ApplicationContextAware接口,通过这个接口的回调方法setApplicationContext(),来获取到一个ApplicationContext对象,进而使用该对象的方法。此处是使用ApplicationContext对象的getBeanDefinitionNames()方法。
三、spring有哪些Aware
名称 | 用途 | 所属容器 | 回调点 |
---|---|---|---|
BeanNameAware | 获取bean名称 | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
BeanClassLoaderAware | 获取bean的类加载器 | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
BeanFactoryAware | 获取bean工厂(建议用下面的ApplicationContextAware) | BeanFactory | Bean后处理器的BeforeInitialization方法之前 |
EnvironmentAware | 获取环境相关信息,如属性、配置信息等 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
EmbeddedValueResolverAware | 获取值解析器 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ResourceLoaderAware | 获取资源加载器 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ApplicationEventPublisherAware | 获取事件广播器,发布事件使用 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
MessageSourceAware | 获取消息资源 | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
ApplicationContextAware | 获取ApplicationContext | ApplicationContext | Bean后处理器的BeforeInitialization方法中 |
前三个Aware接口:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware是在使用BeanFactory方式初始化容器时调用的,所有bean都可以使用。如下:
Resource classPathResource = new ClassPathResource("applicationContext.xml");
BeanFactory xmlBeanFactory = new XmlBeanFactory(classPathResource);
后六个Aware接口是使用ApplicationContext的方式初始化容器时,才会起作用。如下:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
不过我们现在使用的容器一般都是ApplicationContext,在此了解一下即可,无需太关注。
四、看下原理
通过上面的讲解,我们大概了解到Aware的功能:bean实现个某某Aware接口,然后这个bean就可以通过实现接口的方法,来接收接口方法传递过来的资源。那么接口方法是何时被调用的呢?我们来看下源码~
1. bean的初始化过程
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 1. 调用Aware方法(重点关注)
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 2. 调用bean后处理器的BeforeInitialization方法(重点关注)
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 3. 调用bean的初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 4. 调用bean后处理器的AfterInitialization方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
该代码片段来自于AbstractAutowireCapableBeanFactory类的initializeBean方法。其中Aware接口方法的回调过程,分别存在于1和2两个步骤中。我们分别看下
2. BeanFactory的3个Aware接口
以下是bean初始化过程的第一个步骤,也就是beanFactory加载bean时硬编码的3个Aware接口的回调,代码如下:
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
// 1. BeanNameAware接口方法的回调
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
// 2. BeanClassLoaderAware接口方法的回调
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
// 3. BeanFactoryAware接口方法的回调
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
3. ApplicationContext的6个Aware接口
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
从这段代码中,似乎看不出来怎么就调用Aware接口的回调方法了,仅看到了调用容器中所有beanPostProcessor的postProcessBeforeInitialization()方法。这里就用到上面表格中标识的所属容器,为什么后面6个Aware接口属于ApplicationContext这个容器了?我们来看下初始化ApplicationContext时的一段代码:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 主要看这一行!
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
// 省略其他无关代码...
}
该代码来自于AbstractApplicationContext类的prepareBeanFactory方法,使用ApplicationContext初始化容器时会执行此步骤,代码如下:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
该方法中创建了一个ApplicationContextAwareProcessor实例,并注册到beanFactory的BeanPostProcessors中。那么后面调用容器中所有beanPostProcessor的postProcessBeforeInitialization()方法时,也会调用ApplicationContextAwareProcessor的postProcessBeforeInitialization()方法,我们看下这个方法
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
AccessControlContext acc = null;
if (System.getSecurityManager() != null &&
(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 调用Aware接口方法
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
// 调用Aware接口方法
invokeAwareInterfaces(bean);
}
return bean;
}
// 具体回调方法
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof Aware) {
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);
}
}
}
五、小结
两种容器中的Aware接口,调用逻辑如下图所示:
其中粉色代表ApplicationFactory方式初始化的容器,回调的Aware接口。
蓝色表示BeanFactory方式初始化容器时,回调的Aware接口。
ApplicationContext方式初始化的容器,包括所有BeanFactory方式初始化容器的所有功能。
- BeanFactory初始化容器方式
- 在加载bean的步骤中,创建bean之后,调用bean后处理器之前,回调表格中的3个Aware接口
- ApplicationContext初始化容器方式
- 调用BeanFactory方式的3个Aware接口;
- 在加载bean之前创建一个ApplicationContextAwareProcessor,注册在AbstractBeanFactory的beanPostProcessors属性中。然后在加载bean的步骤中,调用bean后处理器的postProcessBeforeInitialization方法过程中,回调表格中的6个Aware接口。