Spring 源码-xxxAware接口回调源码分析

 2023-01-21
原文作者:hsfxuebao 原文地址:https://juejin.cn/post/7134151216912662541

欢迎大家关注 github.com/hsfxuebao ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈

Spring提供了一种机制,让bean在实例化的时候,能够感知(获取)容器中的一些组件,即Aware接口回调的方式。这种机制一般是Spring框架内部使用。

1. 常用Aware接口

Aware 作用
BeanFactoryAware 获取当前BeanFactory,这样可以调用容器的服务
BeanClassLoaderAware 获取类类加载器
BeanNameAware 获取容器中Bean的名称
ApplicationContextAware t同BeanFactory
MessageSourceAware 获取MessageSource相关文本信息
ApplicationEventPublisherAware 发布事件
ResourceLoaderAware 获取资源加载器,这样获取外部资源文件
EnvironmentAware 环境信息
EmbeddedValueResolverAware
ApplicationStartupAware

2. 测试用例

    @Component
    public class PersonAware implements ApplicationContextAware, MessageSourceAware {
    
    // @Autowired
       ApplicationContext context;  //可以要到ioc容器
    
       MessageSource messageSource;
    
       public ApplicationContext getContext() {
          return context;
       }
       public void setContext(ApplicationContext context) {
          this.context = context;
       }
    
       @Override
       public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
          this.context = applicationContext;
       }
    
       @Override
       public void setMessageSource(MessageSource messageSource) {
          this.messageSource = messageSource;
    
       }
    }

在回调方法上打上debug,就可以看到整个方法的执行时机。

3. 源码分析

3.1 原理

在这些Aware中,底层实现主要分为两种:

  • invokeAwareMethods(beanName, bean);

    • BeanNameAware
    • BeanClassLoaderAware
    • BeanFactoryAware
  • BeanPostProcessor,bean后置处理器ApplicationContextAwareProcessor

    • 剩下的7个都是通过后置处理器实现的

3.2 invokeAwareMethods(beanName, bean);

在创建bean的核心方法initializeBean()中,创建好bean后,都会先调用invokeAwareMethods(beanName, bean);,再进行初始化。

    protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
       if (System.getSecurityManager() != null) {
          AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
             invokeAwareMethods(beanName, bean);
             return null;
          }, getAccessControlContext());
       }
       else {
          // todo 组件有Aware接口,先Aware; BeanNameAware BeanClassLoaderAware BeanFactoryAware
          invokeAwareMethods(beanName, bean);
       }
    
       ...
       return wrappedBean;
    }

若这个bean为一个Aware,就去尝试调用一些回调方法。在这个方法中,有三种Aware会在这个方法中被调用:BeanNameAware、BeanClassLoaderAware、BeanFactoryAware。

    private void invokeAwareMethods(String beanName, Object bean) {
       if (bean instanceof Aware) {
          if (bean instanceof BeanNameAware) {
             ((BeanNameAware) bean).setBeanName(beanName);
          }
          if (bean instanceof BeanClassLoaderAware) {
             ClassLoader bcl = getBeanClassLoader();
             if (bcl != null) {
                ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
             }
          }
          if (bean instanceof BeanFactoryAware) {
             ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
          }
       }
    }

3.3 bean后置处理器ApplicationContextAwareProcessor

其余的Aware是由BeanPostProcessor来实现的,实现类为ApplicationContextAwareProcessor。

Spring5源码5-Bean生命周期后置处理器,我们已经说过beanPostProcessor的前置处理都是在applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName)中被一一执行。

    public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
    			throws BeansException {
    
    		Object result = existingBean;
    		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                //调用postProcessBeforeInitialization
    			Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
    			if (current == null) {
    				return result;
    			}
    			result = current;
    		}
    		return result;
    	}

经过一些安全验证,最终会调用invokeAwareInterfaces(bean):

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
             bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
             bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||
             bean instanceof ApplicationStartupAware)) {
          return bean;
       }
    
       AccessControlContext acc = null;
    
       if (System.getSecurityManager() != null) {
          acc = this.applicationContext.getBeanFactory().getAccessControlContext();
       }
    
       if (acc != null) {
          AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
             invokeAwareInterfaces(bean);
             return null;
          }, acc);
       }
       else {
          // todo 执行xxxAware的回调
          invokeAwareInterfaces(bean);
       }
    
       return bean;
    }

逻辑也很简单,判断这个Aware是哪个Aware,就强制转换调用。

    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);
       }
    }

那么,问题来了,ApplicationContextAwareProcessor后置处理器是在什么时候注入到容器中呢? 我们直接看refresh()prepareBeanFactory(beanFactory),该方法中会设置一些后置处理器等。

    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    
       // 添加一些后置处理器
       // 判断当前组件是否实现xxxAware接口,准备一个处理Aware接口的后置处理器
       beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
       ...
    }

参考文章

Spring5源码注释github地址
Spring源码深度解析(第2版)
spring源码解析
Spring源码深度解析笔记
Spring注解与源码分析
Spring注解驱动开发B站教程