什么是 Spring Aware?一篇文章快速上手并搞懂实现原理

什么是 Aware 接口

源码对Aware接口的注释是这样的:

A marker superinterface indicating that a bean is eligible to be notified by the Spring container of a particular framework object through a callback-style method. The actual method signature is determined by individual subinterfaces but should typically consist of just one void-returning method that accepts a single argument.

Aware 接口是「标记接口」,实现了 Aware 接口的 Bean,能够被 Spring 通过回调的方式,获取到一些与 Spring 容器相关的信息,比如 ApplicationContext,BeanFactory 等等。

说白了,想要让一个类获取 Spring 容器相关的信息,或者说持有 Spring 信息比如 ApplicationContext,这时候就得实现 Aware 接口了。

Aware 快速开始

这里以BeanFactoryAware为例:

java 复制代码
 @Component
 public class TestAware implements BeanFactoryAware {
 ​
     private BeanFactory beanFactory;
 ​
     @Override
     public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
         this.beanFactory = beanFactory;
         System.out.println("Aware 接口调用 获取到 BeanFactory");
     }
 ​
     public Object get(String name){
         return beanFactory.getBean(name);
     }
 }

实现对应的 Aware 接口,就可以拿到对应的实例对象。

Aware 的实现原理

对于 Aware 接口,它本质是 A marker superinterface,是一个标记接口,熟悉 BeanPostProcessor 的同学们就有话要说了。

下面是 BeanPostProcessor 的 Javadoc:

Typically, post-processors that populate beans via marker interfaces or the like will implement postProcessBeforeInitialization

关注这几个词,populate beans via marker interfaces,是 通过标记接口填充bean 的意思,这不就是 Aware 接口吗。但根据 Aware 接口提供的信息不同,实现方式也会有所不同。

开始读源码

在 initializeBean 方法中,首先执行 invokeAwareMethods 方法。

java 复制代码
     protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
 ​
         // 1. Aware
         invokeAwareMethods(beanName, bean);
 ​
         // 2. BeanPostProcessorsBeforeInitialization
         Object wrappedBean = bean;
         if (mbd == null || !mbd.isSynthetic()) {
             wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
         }
 ​
         // 3. InitMethods
             invokeInitMethods(beanName, wrappedBean, mbd);
         // 4. BeanPostProcessorsAfterInitialization
         if (mbd == null || !mbd.isSynthetic()) {
             wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
         }
 ​
         return wrappedBean;
     }

invokeAwareMethods 会处理下面这几个 Aware 接口:

java 复制代码
 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) {
           // 回调 setBeanFactory 
          ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
       }
    }
 }

而在 applyBeanPostProcessorsBeforeInitialization 方法中,有这么几个 BeanPostProcessors:

ApplicationContextAwareProcessor 长这样,这个类提供的是 embeddedValueResolver 和 ApplicationContext 相关信息:

java 复制代码
 /*
 BeanPostProcessor implementation that supplies the ApplicationContext, Environment, or StringValueResolver for the ApplicationContext to beans that implement the EnvironmentAware, EmbeddedValueResolverAware, ResourceLoaderAware, ApplicationEventPublisherAware, MessageSourceAware, and/or ApplicationContextAware interfaces.
 */ 
 class ApplicationContextAwareProcessor implements BeanPostProcessor {
 ​
    private final ConfigurableApplicationContext applicationContext;
     
    @Override
    @Nullable
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       // 不需要回调的情况
       if (!(... || bean instanceof ApplicationStartupAware)) {
          return bean;
       }
       // 回调
       invokeAwareInterfaces(bean);
        
       return bean;
    }
     
    // 回调方法 
    private void invokeAwareInterfaces(Object bean) {
         // ... 
       if (bean instanceof ApplicationContextAware) {
          ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
       }
    }
 ​
 }

而 WebApplicationContextServletContextAwareProcessor 提供的是 WebApplicationContextServletContext 相关信息,它的 Before 处理是这样的:

java 复制代码
 /*
 Can be used when registering the processor can occur before the ServletContext or ServletConfig have been initialized.
 */
 @Override
 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    if (getServletContext() != null && bean instanceof ServletContextAware) {
       ((ServletContextAware) bean).setServletContext(getServletContext());
    }
    if (getServletConfig() != null && bean instanceof ServletConfigAware) {
       ((ServletConfigAware) bean).setServletConfig(getServletConfig());
    }
    return bean;
 }

至此,Aware 接口就基本分析完毕了。最后留有一个疑问是:为什么 invokeAwareMethods 方法处理的 Aware 接口和其它 Aware 接口的处理方式不同?我找到一个 issue 可能和这有关:Support Aware interfaces for ImportBeanDefinitionRegistrar [SPR-9568],感兴趣的可以尝试看一下,也欢迎在评论区留下你的答案。

相关推荐
一只叫煤球的猫3 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9653 小时前
tcp/ip 中的多路复用
后端
bobz9653 小时前
tls ingress 简单记录
后端
皮皮林5514 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友5 小时前
什么是OpenSSL
后端·安全·程序员
bobz9655 小时前
mcp 直接操作浏览器
后端
前端小张同学7 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook7 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康8 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在8 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net