Spring Aware 介绍

此次必定?
此次必定?

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

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

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

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 接口app

public interface Aware {
 } 复制代码

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

BeanNameAware

public interface BeanNameAware extends Aware {
 void setBeanName(String name); } 复制代码

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

<bean id="customer" class="com.demo.aware.Customer">
 <constructor-arg name="person">  <bean class="com.demo.aware.Person">  <property name="name" value="coderLi"/>  <property name="address" value="china"/>  <property name="age" value="666"/>  </bean>  </constructor-arg> </bean>  <bean id="cat" class="com.demo.aware.CatFactory"/> 复制代码

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

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"); 复制代码

打印的结果就是:this

bean Name aware [bean Name is] :com.demo.aware.Person#71a794e5
bean Name aware [bean Name is] :cat 复制代码

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

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

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

第二个问题、其实二者的 key 同样是彻底没有问题的、往前翻我分析 getBean 流程的文章能够知道。这里就不重复了

其余

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

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 的、

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

那这个 ApplicationContextAwareProcessor 何时添加到 Spring 中啊

而这个方法则是在 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 实现类

此次必定?
此次必定?
群聊
群聊