Spring Aware 介绍

这次一定?

读完这篇文章你将会收获到

  • Aware 的使用和介绍
  • BeanFactoryAware 的触发时机
  • ApplicationContextAware 的触发时机以及它通过扩展 BeanPostProcessor 来实现

我们在 getBean 流程中曾经谈到过 Spring 回调 Aware 接口

Spring Aware 介绍_第1张图片

Spring Aware 介绍_第2张图片

    private void invokeAwareMethods(final String beanName, final 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);
            }
        }
    }

我们今天就来聊一下 Aware 接口

public interface Aware {

}

一个空的接口、啥都没有、看注释说它只是一个标志性的接口、实现该接口的 bean 会被 Spring 以回调的方式进行通知、告诉你某个阶段某件事情发生了

BeanNameAware

public interface BeanNameAware extends Aware {
    void setBeanName(String name);
}

这个我们举两个有意思的例子,一个是内部 bean 、一个是 factoryBean


   
      
         
         
         
      
   


具体的类就不贴了、没啥逻辑、CatFactory 就实现了 Spring 提供的 FactoryBean 接口。然后我们在 PersonCatFactory 中实现了接口 BeanNameAware 、并打印其参数 name

Resource resource = new ClassPathResource("aware/coderLi.xml");
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions(resource);
defaultListableBeanFactory.getBean("customer");
defaultListableBeanFactory.getBean("cat");

打印的结果就是:

bean Name aware [bean Name is] :com.demo.aware.Person#71a794e5
bean Name aware [bean Name is] :cat

我们打断点在它们 getBean 之后,针对下面图片的结果你是否有疑惑呢

Spring Aware 介绍_第3张图片

第一个是内部 bean Person 对象不在 Spring 的容器中、但是它却触发了 Aware 接口的回调 , 第二个是第一级缓存和 beanFactory 缓存中 key 都是 cat

第一个问题其实很简单、主要是构建 Customer 的构造函数的参数 Person 的时候、在 BeanDefinitionValueResolver#resolveInnerBean 中直接调用了 createBean 方法、然后就到了 doCreateBean 、之后就回调 Aware 接口、但是没用放到 Spring 容器中

第二个问题、其实两者的 key 一样是完全没有问题的、往前翻我分析 getBean 流程的文章可以知道。这里就不重复了

其他

至于 BeanClassLoaderAwareBeanFactoryAware 就不演示代码了、挺简单的使用。

Spring Aware 介绍_第4张图片

Spring 里面比较常见的 Aware 接口

我们看到很多像 ApplicationContextAware 或者 EnvironmentAwareAware 接口、并没有在 invokeAwareMethods 中被调用到、因为其实这些都是在使用 ApplicationContext 的时候才会被触发的、具体是在哪里被触发调用呢?

我们可以看到 ApplicationContextAwareProcessor#invokeAwareInterfaces

中就写了这么一段代码

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

ApplicationContextAwareProcessor 实现了 BeanPostProcessor 的、

Spring Aware 介绍_第5张图片

那这样子的话就是在 doCreateBean 的时候、通过 initializeBean 进行回调了

Spring Aware 介绍_第6张图片

那这个 ApplicationContextAwareProcessor 什么时候添加到 Spring 中啊

Spring Aware 介绍_第7张图片

而这个方法则是在 refresh 方法中被调用了,而 refresh 的调用就不用介绍了把

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
    this(new String[] {configLocation}, true, null);
}

public ClassPathXmlApplicationContext(
      String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}

其实 Spring 挺有意思的、将这个 ApplicationContextAwareProcessor 作为其第一个 BeanPostProcessor 接口、那么就能保证 Aware 接口被先回调、然后才到用户的 BeanPostProcessor 实现类

这次一定?

群聊

你可能感兴趣的:(spring,后端,java,程序员,源码分析)