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方法传入组件
相关文章
相关标签/搜索