目錄
一、概述
二、執行個體分析
三、源碼追蹤
四、總結
一、概述
不管是我們平時開發中,還是在看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;
}
}
-
- 判斷是否是xxxAware接口
- 如果是,則擷取xxx,調用setxxx方法進行注入
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在初始化的時候利用
後置處理器判斷這個bean是否是xxxProcess
接口xxxAware
- 如果是,則調用相應的set方法傳入元件