文章目录
- Aware接口
- 一、子接口
- 二、常用子接口
- 三、回调时机
- 3.1 BeanPostProcessor之前处理
- 3.2 BeanPostProcessor中处理
- 3.3 特殊
- 3.3.1 ImportAware
- 3.3.2 LoadTimeWeaverAware
- 3.3.2 NotificationPublisherAware
- 四、小结
- 五、参考
Aware接口
- Aware是Spring的一个重要顶层接口,包含很多子接口,相关的接口功能都很类似,Aware体系接口可以理解为一种能力,
它表示spring容器会通过回调方法来将特定的框架对象通知给这个bean。有点拗口,举个例子,Aware的一个子接口ApplicationContextAware
public interface ApplicationContextAware extends Aware {
void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
- 在这里,setApplicationContext就是前面所说的回调方法,applicationContext对象就是特定的框架对象,在bean初始化的某个特定时机,会调
用该方法,将applicationContext对象传递给实现了ApplicationContextAware接口的bean。
一、子接口
- Aware是顶层接口,包含很多子接口,每一个子接口代表具体的一种场景,比如前面的ApplicationContextAware就是具体的一种。
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- EnvironmentAware
- ApplicationContextAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ImportAware
- LoadTimeWeaverAware
- NotificationPublisherAware
二、常用子接口
- 常用的子接口通常都是用来对bean注入一个属性,比如BeanNameAware将beanName注入给bean。下面表格中小结了常用的接口功能,
其中感知某种属性实际上就是一个回调的set方法将对应的属性set到当前的bean中。
接口 | 作用 | 备注 |
BeanNameAware | 感知Bean的beanName | 获取bean名称 |
BeanClassLoaderAware | 感知当前Bean工厂用来加载当前Bean的ClassLoader | 主要是框架的类实现该接口,使用BeanClassLoader加载外部对应的Resource资源 |
BeanFactoryAware | 感知BeanFactoryAware | 获取IOC容器 |
ApplicationContextAware | 感知ApplicationContextAware | 获取应用上下文 |
EnvironmentAware | 感知Environment | 获取Environment |
三、回调时机
- 这部分我们看看这些回调方法的调用时机。
3.1 BeanPostProcessor之前处理
接口 |
BeanNameAware |
BeanClassLoaderAware |
BeanFactoryAware |
- 我们很好奇Aware子接口的方法是在什么时候调用的,这个问题实际上也是bean的生命周期的一部分,方法的回调肯定是在生命周期的某个阶段。
我们通过bean的生命周期源码的方法跟进,跟进到
AbstractAutowireCapableBeanFactory#initializeBean()#1685
(可以参考03-spring BeanPostProcessor文章中的BeanPostProcessor方法的调用时机小节)
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.调用BeanPostProcessor前置方法
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
//3.初始化过程
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
//4.调用BeanPostProcessor后置方法
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
- AbstractAutowireCapableBeanFactory#invokeAwareMethods#line 1716
//invokeAwareMethods方法会判断bean是否实现了对应的接口,然后调用对应接口的回调方法,包含BeanNameAware,BeanClassLoaderAware,BeanFactoryAware这三种。
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);
}
}
}
- 通过上面的2个方法我们可以看到,如果一个bean实现了BeanNameAware,BeanClassLoaderAware和BeanFactoryAware三个接口中的某一个或者多个的话,那么
对应的回调方法会在BeanPostProcessor后置处理器的前置方法之前被调用,即遵循这样的处理流程:Aware回调方法->BeanPostProcessor前置方法->Bean初始化->BeanPostProcessor后置方法
3.2 BeanPostProcessor中处理
- 我们在3.1其实只看到了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware这三个接口的调用源码,也知道了对应回调方法的调用时机。那么其余的接口回调方法呢?
接口 |
EnvironmentAware |
ApplicationContextAware |
EmbeddedValueResolverAware |
ResourceLoaderAware |
ApplicationEventPublisherAware |
MessageSourceAware |
- 上面的5个接口的回调方法是在ApplicationContextAwareProcessor类中处理的,一看类名我们就知道这个是一个BeanPostprocessor接口的实现类,如下:
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
/**
* Create a new ApplicationContextAwareProcessor for the given context.
*/
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
//重写BeanPostProcessor的前置方法,进行Aware子接口的相关判断和回调方法执行
@Override
@Nullable
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>) () -> {
invokeAwareInterfaces(bean);
return null;
}, acc);
}
else {
invokeAwareInterfaces(bean);
}
return bean;
}
//执行回调方法,包括EnvironmentAware,ApplicationContextAware,EmbeddedValueResolverAware,ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware五个接口的处理
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);
}
}
}
//重写BeanPostProcessor的后置方法,直接返回bean
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}
- 代码逻辑比较简单,ApplicationContextAwareProcessor是一个BeanPostprocessor接口实现类,因此他会处理每一个普通的bean,在处理时候在他的前置处理方法中会判断是否实现了指定的接口,
并调用指定的方法。因此这里的五个接口的处理是在BeanPostprocessor的前置处理方法中调用的。即遵循这样的处理流程:BeanPostProcessor前置方法(Aware回调方法)->Bean初始化->BeanPostProcessor后置方法
3.3 特殊
接口 |
ImportAware |
LoadTimeWeaverAware |
NotificationPublisherAware |
3.3.1 ImportAware
- ImportAware接口方法的回调是在ConfigurationClassPostProcessor.ImportAwareBeanPostProcessor类中实现的,分析代码发现ImportAwareBeanPostProcessor也是BeanPostProcessor的
子类,并且也是在BeanPostProcessor的后置回调方法中执行的,这一点和3.2是一样的。如下:
private static class ImportAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
private final BeanFactory beanFactory;
public ImportAwareBeanPostProcessor(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) {
// Inject the BeanFactory before AutowiredAnnotationBeanPostProcessor's
// postProcessPropertyValues method attempts to autowire other configuration beans.
if (bean instanceof EnhancedConfiguration) {
((EnhancedConfiguration) bean).setBeanFactory(this.beanFactory);
}
return pvs;
}
//在BeanPostProcessor的后置回调方法中回调ImportAware.setImportMetadata方法
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof ImportAware) {
ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(bean.getClass().getSuperclass().getName());
if (importingClass != null) {
((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
}
- 关于ImportAware接口的作用,发现资料不多,我用代码试验了是这样的作用。比如我们自己写的一个配置类A,在配置类A中import一个配置类B,类B实现ImportAware接口,那么在类B的
setImportMetadata方法中就可以获取关于类A的很多元信息,可能主要用在框架内部,暂时没有去研究它的使用场景,示例代码如下:
@Import(Cap11Config.class)
@Configuration
@ComponentScan("com.intellif.ch11")
@PropertySource(value="classpath:/application-01.properties")
public class Cap11MainConfig {
}
@Configuration
public class Cap11Config implements ImportAware {
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
System.out.println("Cap11Config setImportMetadata function execute: " + importMetadata.toString());
Set<String> annotationTypes = importMetadata.getAnnotationTypes();
for (String annotation: annotationTypes) {
System.out.println(annotation);
}
}
}
//部分打印如下,可以看到在Cap11Config配置类中获得了Cap11MainConfig配置类的相关信息:
Cap11Config setImportMetadata function execute: org.springframework.core.type.StandardAnnotationMetadata@670002
org.springframework.context.annotation.Import
org.springframework.context.annotation.Configuration
org.springframework.context.annotation.ComponentScan
org.springframework.context.annotation.PropertySource
3.3.2 LoadTimeWeaverAware
- LoadTimeWeaverAware接口的实现类,在框架源码中只有AspectJWeavingEnabler,其原理和AOP相关,在这里就不分析了,后续关于AOP的文章再做分析。
3.3.2 NotificationPublisherAware
- NotificationPublisherAware是用来注入Spring JMX通知发布者,使用不多,在框架中都未找到源码,暂不做分析。
四、小结
- 本文我们主要是小结了Aware接口体系的常用接口,简单分析了对应接口的回调方法的调用时机,Aware接口本身提供的功能比较容易理解,实际上就是让bean在其
生命周期过程中获取到容器的一些信息(一般情况下可能容器作为bean的管理者,bean不需要知道容器的习惯细节,但是可能也会有一些情况bean需要知道容器的一些
信息,来帮助bean完成一些功能,比如注入上下文来获取其他的bean,注入beanName等)。Aware的回调接口的时机一部分接口是在BeanPostProcessor前置处理方法之
前调用,一部分接口直接就是在BeanPostProcessor前置处理方法中调用的,这样的情况实际上是由一个BeanPostProcessor的子类来完成处理的。 - 结合Bean的生命周期和Aware回调方法的调用时机,我们可能在整体上掌握的更好。