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

blogg55

1、概述

無論是咱們平時開發中,仍是在看spring源碼中,都會遇到Aware這個接口,Aware的英文意思:意識到,察覺到,發覺,發現。從英文翻譯來看,Aware作的事情應該是發現某一個東西。java

註釋的大體意思是:Aware是一個標記性的超接口(頂級接口),指示了一個Bean有資格經過回調方法的形式獲取Spring容器底層組件。實際回調方法被定義在每個子接口中,並且一般一個子接口只包含一個接口一個參數而且返回值爲void的方法。spring

說白了:只要實現了Aware子接口的Bean都能獲取到一個Spring底層組件。markdown

自定義組件時,想要使用spring容器底層的一些組件,好比ApplicationContext、Beanfactory,xxx等,只須要讓自定義組件實現xxxAware,在對象實例化的時候,會把spring底層的一些組件注入到自定義的bean中。經過查看源碼,能夠看到有這麼多的接口,每一個接口都有都對應spring相應的底層,好比:app

  • 實現BeanNameAware接口的bean:獲取BeanName
  • 實現BeanFactoryAware接口的bean:取到BeanFactory組件對象
  • 實現EnvironmentAware接口的bean:獲取到Environment組件對象
  • 實現XXXAware接口的bean:經過實現的setXXX方法就能夠獲取到XXX組件對象

image-20210314154105087

2、實例分析

這裏就以一些經常使用的接口進行舉例,實現其接口,經過這些接口使用spring底層的一些組件post

// 啓動類
@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();
    }
}
複製代碼

運行啓動類,能夠看到輸出結果以下:this

image-20210314225234698

這裏對Aware的三個接口進行了舉例,分別是ApplicationContextAware、BeanNameAware、EmbeddedValueResolverAwarespa

  • ApplicationContextAware:經過上下文環境對象獲得Spring容器中的Bean
  • BeanNameAware:獲取bean的名字
  • EmbeddedValueResolverAware:解析一些字符串、佔位符等

3、源碼追蹤

其實每個子接口,都是利用相應的xxxProcess來進行處理的,也就是相應的後置處理器,而這些xxxProcess都是BeanPostProcess的接口,好比ApplicationContextAware就是經過ApplicationContextAwareProcess來進行處理的,ApplicationContextAwareProcess實現了BeanPostProcess翻譯

這裏就以ApplicationContextAware,經過Debug調試進行源碼追蹤,看看是如何給User把ApplicationContext給注入進來的:調試

在setApplicationContext方法進行斷點調試:code

image-20210314232448824

經過方法調用棧,能夠看到ApplicationContextAwareProcessor調用postProcessBeforeInitialization方法,

image-20210314232914353

  • 判斷是不是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傳入,作以下處理:

  1. 判斷是不是xxxAware接口
  2. 若是是,則獲取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);
    }

}
複製代碼

4、總結

  • bean在初始化的時候利用xxxProcess後置處理器判斷這個bean是不是xxxAware接口
  • 若是是,則調用相應的set方法傳入組件
相關文章
相關標籤/搜索