讀完這篇文章你將會收穫到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
實現類