天天看點

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中Aware接口 -【Spring底層原理】

二、執行個體分析

這裡就以一些常用的接口進行舉例,實作其接口,通過這些接口使用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();
    }
}
      

運作啟動類,可以看到輸出結果如下:

Spring中Aware接口 -【Spring底層原理】
這裡對Aware的三個接口進行了舉例,分别是ApplicationContextAware、BeanNameAware、EmbeddedValueResolverAware
  • ApplicationContextAware:通過上下文環境對象得到Spring容器中的Bean
  • BeanNameAware:擷取bean的名字
  • EmbeddedValueResolverAware:解析一些字元串、占位符等

三、源碼追蹤

其實每一個子接口,都是利用相應的​

​xxxProcess​

​​來進行處理的,也就是相應的後置處理器,而這些​

​xxxProcess​

​​都是​

​BeanPostProcess​

​​的接口,比如​

​ApplicationContextAware​

​​就是通過​

​ApplicationContextAwareProcess​

​​來進行處理的,​

​ApplicationContextAwareProcess​

​​實作了​

​BeanPostProcess​

這裡就以​

​ApplicationContextAware​

​,通過Debug調試進行源碼追蹤,看看是如何給User把ApplicationContext給注入進來的:

在setApplicationContext方法進行斷點調試:

Spring中Aware接口 -【Spring底層原理】

通過方法調用棧,可以看到​

​ApplicationContextAwareProcessor​

​​調用​

​postProcessBeforeInitialization​

​方法,

Spring中Aware接口 -【Spring底層原理】
  • 判斷是否是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;
    }
}
      
  1. 判斷是否是xxxAware接口
  2. 如果是,則擷取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在初始化的時候利用​

    ​xxxProcess​

    ​​後置處理器判斷這個bean是否是​

    ​xxxAware​

    ​接口
  • 如果是,則調用相應的set方法傳入元件