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

快来打我* 2021-09-21 20:54 473阅读 0赞

目录

一、概述

二、实例分析

三、源码追踪

四、总结


一、概述

不管是我们平时开发中,还是在看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组件对象

image-20210314154105087

二、实例分析

这里就以一些常用的接口进行举例,实现其接口,通过这些接口使用spring底层的一些组件

  1. // 启动类
  2. @Test
  3. public void TestMain() {
  4. // 创建IOC容器
  5. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
  6. }
  7. // 待注入的bean
  8. @Component
  9. public class User implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
  10. private ApplicationContext applicationContext;
  11. // 通过上下文环境对象得到Spring容器中的Bean
  12. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  13. System.out.println("传入的IOC:" + applicationContext);
  14. this.applicationContext = applicationContext;
  15. }
  16. // 获取bean的名字
  17. public void setBeanName(String s) {
  18. System.out.println("当前bean的名字:" + s);
  19. }
  20. // 解析一些字符串、占位符等
  21. public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
  22. String resolveStringValue = stringValueResolver.resolveStringValue("你好${os.name}");
  23. System.out.println("解析的字符串是:" + resolveStringValue);
  24. }
  25. }
  26. // 配置类
  27. @Configuration
  28. public class AppConfig {
  29. @Bean
  30. public User User(){
  31. return new User();
  32. }
  33. }

运行启动类,可以看到输出结果如下:

image-20210314225234698

这里对Aware的三个接口进行了举例,分别是ApplicationContextAware、BeanNameAware、EmbeddedValueResolverAware

  • ApplicationContextAware:通过上下文环境对象得到Spring容器中的Bean
  • BeanNameAware:获取bean的名字
  • EmbeddedValueResolverAware:解析一些字符串、占位符等

三、源码追踪

其实每一个子接口,都是利用相应的xxxProcess来进行处理的,也就是相应的后置处理器,而这些xxxProcess都是BeanPostProcess的接口,比如ApplicationContextAware就是通过ApplicationContextAwareProcess来进行处理的,ApplicationContextAwareProcess实现了BeanPostProcess

这里就以ApplicationContextAware,通过Debug调试进行源码追踪,看看是如何给User把ApplicationContext给注入进来的:

在setApplicationContext方法进行断点调试:

image-20210314232448824

通过方法调用栈,可以看到ApplicationContextAwareProcessor调用postProcessBeforeInitialization方法,

image-20210314232914353

  • 判断是否是xxxAware接口,判断是,则继续往下
  • 通过invokeAwareInterfaces里面进行注入
  1. @Nullable
  2. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  3. // 判断是否是xxxAware接口,判断是,则继续往下
  4. if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware) && !(bean instanceof ApplicationStartupAware)) {
  5. return bean;
  6. } else {
  7. AccessControlContext acc = null;
  8. if (System.getSecurityManager() != null) {
  9. acc = this.applicationContext.getBeanFactory().getAccessControlContext();
  10. }
  11. if (acc != null) {
  12. AccessController.doPrivileged(() -> {
  13. this.invokeAwareInterfaces(bean);
  14. return null;
  15. }, acc);
  16. } else {
  17. // 在这个方法进行相应的注入
  18. this.invokeAwareInterfaces(bean);
  19. }
  20. return bean;
  21. }
  22. }

点开invokeAwareInterfaces方法,这个bean参数就是User对象,将需要注入的bean传入,做如下处理:

  1. 判断是否是xxxAware接口
  2. 如果是,则获取xxx,调用setxxx方法进行注入

这里以ApplicationContextAware为例,实现了ApplicationContextAware接口,则将User对象转成ApplicationContextAware接口调用setApplicationContext方法进行注入

  1. private void invokeAwareInterfaces(Object bean) {
  2. if (bean instanceof EnvironmentAware) {
  3. ((EnvironmentAware)bean).setEnvironment(this.applicationContext.getEnvironment());
  4. }
  5. if (bean instanceof EmbeddedValueResolverAware) {
  6. ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver(this.embeddedValueResolver);
  7. }
  8. if (bean instanceof ResourceLoaderAware) {
  9. ((ResourceLoaderAware)bean).setResourceLoader(this.applicationContext);
  10. }
  11. if (bean instanceof ApplicationEventPublisherAware) {
  12. ((ApplicationEventPublisherAware)bean).setApplicationEventPublisher(this.applicationContext);
  13. }
  14. if (bean instanceof MessageSourceAware) {
  15. ((MessageSourceAware)bean).setMessageSource(this.applicationContext);
  16. }
  17. if (bean instanceof ApplicationStartupAware) {
  18. ((ApplicationStartupAware)bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
  19. }
  20. if (bean instanceof ApplicationContextAware) {
  21. ((ApplicationContextAware)bean).setApplicationContext(this.applicationContext);
  22. }
  23. }

四、总结

  • bean在初始化的时候利用xxxProcess后置处理器判断这个bean是否是xxxAware接口
  • 如果是,则调用相应的set方法传入组件

发表评论

表情:
评论列表 (有 0 条评论,473人围观)

还没有评论,来说两句吧...

相关阅读

    相关 spring-aware接口

    在springmvc中如果某个bean需要获取spring 的某些容器,可以通过实现其接口的方式,来获得,以此达到在Bean被初始后,能进行CRUD、数据源动态注入到全局应用等