likes
comments
collection
share

Spring5源码6-xxxAware接口回调源码分析

作者站长头像
站长
· 阅读数 15

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

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

1. 常用Aware接口

Aware作用
BeanFactoryAware获取当前 BeanFactory,这样可以调用容器的服务
BeanClassLoaderAware获取类类加载器
BeanNameAware获取容器中 Bean 的名称
ApplicationContextAwaret同BeanFactory
MessageSourceAware获取 Message Source 相关文本信息
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站教程