Spring中Aware接口 -【Spring底层原理】
目录
一、概述
二、实例分析
三、源码追踪
四、总结
一、概述
不管是我们平时开发中,还是在看spring源码中,都会遇到Aware这个接口,Aware的英文意思:意识到,察觉到,发觉,发现。从英文翻译来看,Aware做的事情应该是发现某一个东西。
注释的大致意思是:Aware是一个标记性的超接口(顶级接口),指示了一个Bean有资格通过回调方法的形式获取Spring容器底层组件。实际回调方法被定义在每一个子接口中,而且通常一个子接口只包含一个接口一个参数并且返回值为void的方法。
说白了:只要实现了Aware子接口的Bean都能获取到一个Spring底层组件。
自定义组件时,想要使用spring容器底层的一些组件,比如ApplicationContext、Beanfactory,xxx等,只需要让自定义组件实现xxxAware,在对象实例化的时候,会把spring底层的一些组件注入到自定义的bean中。通过查看源码,可以看到有这么多的接口,每个接口都有都对应spring相应的底层,比如:
- 实现BeanNameAware接口的bean:获取BeanName
- 实现BeanFactoryAware接口的bean:取到BeanFactory组件对象
- 实现EnvironmentAware接口的bean:获取到Environment组件对象
- 实现XXXAware接口的bean:通过实现的setXXX方法就可以获取到XXX组件对象
二、实例分析
这里就以一些常用的接口进行举例,实现其接口,通过这些接口使用spring底层的一些组件
// 启动类
@Test
public void TestMain() {
// 创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
}
// 待注入的bean
@Component
public class User implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
// 通过上下文环境对象得到Spring容器中的Bean
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("传入的IOC:" + applicationContext);
this.applicationContext = applicationContext;
}
// 获取bean的名字
public void setBeanName(String s) {
System.out.println("当前bean的名字:" + s);
}
// 解析一些字符串、占位符等
public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
String resolveStringValue = stringValueResolver.resolveStringValue("你好${os.name}");
System.out.println("解析的字符串是:" + resolveStringValue);
}
}
// 配置类
@Configuration
public class AppConfig {
@Bean
public User User(){
return new User();
}
}
运行启动类,可以看到输出结果如下:
这里对Aware的三个接口进行了举例,分别是ApplicationContextAware、BeanNameAware、EmbeddedValueResolverAware
- ApplicationContextAware:通过上下文环境对象得到Spring容器中的Bean
- BeanNameAware:获取bean的名字
- EmbeddedValueResolverAware:解析一些字符串、占位符等
三、源码追踪
其实每一个子接口,都是利用相应的xxxProcess
来进行处理的,也就是相应的后置处理器,而这些xxxProcess
都是BeanPostProcess
的接口,比如ApplicationContextAware
就是通过ApplicationContextAwareProcess
来进行处理的,ApplicationContextAwareProcess
实现了BeanPostProcess
这里就以ApplicationContextAware
,通过Debug调试进行源码追踪,看看是如何给User把ApplicationContext给注入进来的:
在setApplicationContext方法进行断点调试:
通过方法调用栈,可以看到ApplicationContextAwareProcessor
调用postProcessBeforeInitialization
方法,
- 判断是否是xxxAware接口,判断是,则继续往下
- 通过invokeAwareInterfaces里面进行注入
@Nullable
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 判断是否是xxxAware接口,判断是,则继续往下
if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
return bean;
} else {
AccessControlContext acc = null;
if (System.getSecurityManager() != null) {
acc = this.applicationContext.getBeanFactory().getAccessControlContext();
}
if (acc != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareInterfaces(bean);
return null;
}, acc);
} else {
// 在这个方法进行相应的注入
this.invokeAwareInterfaces(bean);
}
return bean;
}
}
点开invokeAwareInterfaces方法,这个bean参数就是User对象,将需要注入的bean传入,做如下处理:
- 判断是否是xxxAware接口
- 如果是,则获取xxx,调用setxxx方法进行注入
这里以ApplicationContextAware为例,实现了ApplicationContextAware接口,则将User对象转成ApplicationContextAware接口调用setApplicationContext方法进行注入
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 ApplicationStartupAware) {
((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
}
}
四、总结
- bean在初始化的时候利用
xxxProcess
后置处理器判断这个bean是否是xxxAware
接口 - 如果是,则调用相应的set方法传入组件
还没有评论,来说两句吧...