写点什么

Spring Aware 你不能不知道的事

用户头像
CoderLi
关注
发布于: 2020 年 06 月 15 日

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

  • ``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`` 接口


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` 接口。然后我们在 `Person``CatFactory` 中实现了接口 `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#71a794e5bean Name aware [bean Name is] :cat
复制代码


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



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


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


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


其他


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



``Spring` 里面比较常见的 `Aware`` 接口


我们看到很多像 ``ApplicationContextAware` 或者 `EnvironmentAware``Aware` 接口、并没有在 `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`` 实现类


发布于: 2020 年 06 月 15 日阅读数: 172
用户头像

CoderLi

关注

微信公众号:CoderLi ,专注于 Java 后端开发 2019.07.14 加入

还未添加个人简介

评论

发布
暂无评论
Spring Aware 你不能不知道的事