读完这篇文章你将会收获到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
以回调的方式进行通知、告诉你某个阶段某件事情发生了编辑器
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
flex
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
都是 cat
spa
第一个问题其实很简单、主要是构建 Customer
的构造函数的参数 Person
的时候、在 BeanDefinitionValueResolver#resolveInnerBean
中直接调用了 createBean
方法、而后就到了 doCreateBean
、以后就回调 Aware
接口、可是没用放到 Spring
容器中3d
第二个问题、其实二者的 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
实现类