读完这篇文章你将会收获到
我们在 ``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`` 实现类
评论