深入分析Spring Aware原理

一、什么是Spring Aware

在Spring学习中,依赖注入是最大的亮点,用户所有的Bean对Spring容器的存在是没有意识的,这样就可以降低Bean之间的耦合
但是在开发中,不可避免需要使用到Spring容器本身的功能和资源。这时,Bean需要意识到Spring容器的存在,才能使用Spring提供的资源,这就是所谓的Spring Aware。

Spring Aware是Spring设计给框架内部使用的,如果使用了Spring Aware,这时Bean将与Spring框架耦合。

二、设计Spring Aware的目的

设计Spring Aware的目的是为了让Bean获得Spring容器内置的组件。
例如:自定义组件要想使用Spring容器底层的一些组件(比如:ApplicationContext、BeanFactory等),此时,只需要让自定义组件实现XxxAware接口即可。此时,Spring在创建对象的时候,会调用XxxAware接口定义的方法(setXxx()方法),注入相关的组件。

常用Aware:

类名 作用
ApplicationContextAware 获得当前应用上下文
BeanNameAware 获取容器中bean名称
BeanClassLoaderAware 获得类加载器
BeanFactoryAware 获得bean工厂
EnviromentAware 获得环境变量
EnvironmentValueResolverAware 获取spring容器加载的properties文件属性值
ResourceLoaderAware 获得资源加载器
ApplicationEventPublisherAware 获得应用程序发布器
MessageSourceAware 获得文本信息

三、XxxAware接口概览

自定义组件实现XxxAware接口:

@Component
public class Employee implements ApplicationContextAware {
    
    
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        this.applicationContext = applicationContext;
    }
}

从Employee类的源码可以看出,实现ApplicationContextAware接口的话,需要实现setApplicationContext()方法。在IOC容器启动并创建Employee对象时,Spring会调用setApplicationContext()方法,并且会将ApplicationContext对象传入到setApplicationContext()方法中,我们只需要在Employee类中定义一个ApplicationContext类型的成员变量来接收setApplicationContext()方法的参数,就可以使用ApplicationContext对象了。

其实,在Spring中,类似于ApplicationContextAware接口的设计有很多,本质上,Spring中类似XxxAware接口都继承了Aware接口,我们来看下Aware接口的源码,如下所示:

package org.springframework.beans.factory;
/**
 * @author Chris Beams
 * @author Juergen Hoeller
 * @since 3.1
 */
public interface Aware {
    
    

}

可以看到,Aware接口是Spring 3.1版本中引入的接口,在Aware接口中,并未定义任何方法。
接下来,我们看看都有哪些接口继承了Aware接口,如下所示:

在这里插入图片描述

扫描二维码关注公众号,回复: 16140970 查看本文章

四、XxxAware接口案例

ApplicationContextAware接口使用的比较多,先来说说这个接口,通过ApplicationContextAware接口可以获取到IOC容器。

首先,创建一个Blue类,并实现ApplicationContextAware接口,在实现的setApplicationContext()中将ApplicationContext输出,如下所示:

package io.mykit.spring.plugins.register.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware {
    
    
    private ApplicationContext applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }
}

我们也可以为Blue类同时实现几个XxxAware接口,例如,使Blue类再实现一个BeanNameAware接口,我们可以通过BeanNameAware接口获取到当前bean在Spring容器中的名称,如下所示:

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware, BeanNameAware {
    
    
    private ApplicationContext applicationContext
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
    
    
        System.out.println("当前bean的名字");
    }

}

接下来,我们再实现一个EmbeddedValueResolverAware接口,我们通过EmbeddedValueResolverAware接口能够获取到StringValue解析器。如下所示:

/**
 * @description 测试ApplicationContextAware接口
 */
public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    
    
    private ApplicationContext applicationContext;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    
    
        System.out.println("传入的ioc:" + applicationContext);
        this.applicationContext = applicationContext;
    }

    @Override
    public void setBeanName(String name) {
    
    
        System.out.println("当前bean的名字");
    }

    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
    
    
        String resolveStringValue = resolver.resolveStringValue("你好${os.name} 年龄:#{20*18}");
        System.out.println("解析后的字符串为:" + resolveStringValue);
    }
}

接下来,我们需要在Blue类上标注@Component注解将Blue类添加到IOC容器中,如下所示:

@Component
public class Blue implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {
    
    }

输出的结果信息如下所示:

当前bean的名字:blue
解析后的字符串为:你好Windows 10 年龄:360
传入的ioc:org.springframework.context.annotation.AnnotationConfigApplicationContext@5ecddf8f

五、XxxAware原理

XxxAware的底层原理是由XxxAwareProcessor类实现的, 例如,我们这里以ApplicationContextAware接口为例,ApplicationContextAware接口的底层原理就是由ApplicationContextAwareProcessor类实现的。从ApplicationContextAwareProcessor类的源码可以看出,其实现了BeanPostProcessor接口,本质上都是后置处理器。

class ApplicationContextAwareProcessor implements BeanPostProcessor

接下来,我们就以分析ApplicationContextAware接口的原理为例,看看Spring是怎么将ApplicationContext对象注入到Blue类中的。
我们在Blue类的setApplicationContext()方法上打一个断点,如下所示:

在这里插入图片描述

接下来,我们以debug的方式来运行

在这里插入图片描述

这里,我们可以看到,实际上ApplicationContext对象已经注入到Blue类中的setApplicationContext()方法中了。我们在IDEA的方法调用栈中选择postProcessBeforeInitialization()方法,如下所示:

在这里插入图片描述

我们双击IDEA中的postProcessBeforeInitialization()方法的调用栈,会在IDEA中自动定位到postProcessBeforeInitialization()方法中,如下所示:

在这里插入图片描述

其实,postProcessBeforeInitialization()方法所在的类就是ApplicationContextAwareProcessor。

我们来看下在postProcessBeforeInitialization()方法中调用的invokeAwareInterfaces()方法,如下所示:

public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    
    
  
  。。。
  invokeAwareInterfaces(bean);
  return bean;
  。。。
  
  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 ApplicationContextAware) {
    
    
          ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
}

总结:

XxxAware原理 (基于Bean的后置处理器执行XxxAware中的回调方法注入组件)
自定义实现XxxAware接口的bean,在被初始化之前会执行BeanPostProcessor.postProcessBeforeInitialization()方法,回调XxxAware接口中的SetXxx方法,将Xxx注入到自定义bean中。

Aware机制源码分析:
初始化Spring容器时,会执行refresh()中的第3个方法prepareBeanFactory(),该方法会向容器中注册ApplicationContextAwareProcessor后置处理器,Spring中的每个bean在初始化之前都会调用BeanPostProcessor.postProcessBeforeInitialization()方法,实现了XxxAware接口的类,就可以被注入Xxx对象的实例。

prepareBeanFactory部分源码:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
    
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));// 添加实现Aware机制的后置处理器
   // 忽略下面这些接口的依赖注入分析
   // spring是通过让bean实现xxxAware接口获取相应的对象的实例的,也就没有必要再通过依赖注入的方式获取xxxAware实例对象了
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
}

猜你喜欢

转载自blog.csdn.net/qq_36602071/article/details/129741747
今日推荐