spring步步前行(IOC)-強擼BeanFactoryPostProcessor
spring爲我們提供的一些由我們自由控制時機的方式除了BeanPostProcessor外,還有一個叫BeanFactoryPostProcessor,我們知道BeanFactoryPostProcessor其作用是允許我們在工廠內所有的bean沒被初始化之前且在加載後,對所有bean的屬性進行修改,相信很多朋友對其作用和意義也是停留在看看,這一篇我們繼續使用一些實例輔助我們理解BeanFactoryPostProcessor
官方解讀
這個接口是允許修改應用上下文中的bean definitions來適配bean的屬性值,其也就是說spring在初始化beanDefinitionMap後爲我們提供了一個允許我們修改beanDefinition內容的契機
感覺和上一篇我們分析的beanPostProcessor很相像,我們再回頭將beanPostProcessor的官方註釋結合起來看看beanPostProcessor與beanFactoryPostProcessor有什麼不同
首先beanPostProcessor
Factory hook that allows for custom modification of new bean instances,
e.g. checking for marker interfaces or wrapping them with proxies.
允許修改新的bean的實例
而beanFactoryPostProcessor官方是這樣描述的
A BeanFactoryPostProcessor may interact with and modify bean
definitions, but never bean instances.
即beanFactoryPostProcessor是修改deanDefinitions而不是修改實例
從這裏我們很清晰的能看出它們倆的不同,beanFactoryPostProcessor修改的是beanDefinition,而beanPostProcessor修改的是bean的實例。那bean的實例與beanDefiniton的關係又是什麼呢?從之前的beanFactory的分析,我們瞭解到beanDefinition是對bean的描述,舉個例子也就是說一個公司打印海報,發現海報上的公司信息有問題,beanPostProcessor的做法就是直接劃掉換上新的,而beanFactoryPostProcessor的做法就是直接重新做一份海報,到這beanFactoryPostProcessor與beanPostProcessor的區別就很明顯了,beanFactoryPostProcessor完全修改屬性,而beanPostProcessor更像臨時修改bean的屬性
這裏我們簡單回顧下beanDefinition:
beanDefinition是對bean實例的描述,包括是否單例,是否抽象,是否懶加載屬性,構造參數等信息,其通過繼承AttributeAccessor賦予了其具備操作屬性相關的方法,繼承BeanMetadataElement來持有bean元數據元素的持有,總的來說就是將bean的信息存儲到這個BeanDefinition相應的屬性中,可根據其信息來反射創建對象
接下來我們看看beanFactoryPostProcessor的接口方法:
既然beanFactoryPostProcessor修改的是beanDefinition,而我們的beanDefinition又存儲在beanFactory內,那麼自然我們要方法上就需要beanFactory作爲參數了
實例
既然和beanPostProcessor很相近,那我們繼續沿用之前的demo好了,對於在beanPostProcessor的我們添加默認值的做法,可能有很多朋友對註解處理覺得不夠優雅,這一次我們改用beanFactoryPostProcessor來實現達到同樣的效果
首先對我們創建的調試bean做調整:
//去掉默認值的註解不在需要,注意提供set方法不然會報錯
public class ClazzBean {
// @SetDefaultValue(defaultValue = "章三")
public String name;
public String clazz;
public String extral;
// @SetDefaultValue(defaultValue = "17213213")
public String phone;
public void setName(String name) {
this.name = name;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public void setExtral(String extral) {
this.extral = extral;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "ClazzBean{" +
"name='" + name + '\'' +
", clazz='" + clazz + '\'' +
", extral='" + extral + '\'' +
", phone='" + phone + '\'' +
'}';
}
}
@Bean("clazzbean")//添加標記 後續通過clazzbean來獲取beanDefinition
public ClazzBean test() {
return new ClazzBean();
}
然後對之前的BeanPostProcessor的postProcessBeforeInitialization內處理註解方法註釋不在需要
接着我們創建一個實現了BeanFactoryPostProcessor的Processor類,如下:
我們的改造就完畢了,跑起來爽一下看看效果:
果然達到同樣的效果,是不是優雅很多,一個字,爽!!
官例介紹
上一次我們舉例了spring中爲我們提供了很多我們可以學習的實例,畢竟耳聽爲虛,眼見爲實,這一次我們通過官方的一個beanFactoryPostProcessor的實現來眼見爲實一次
我們以一個過時警告的應用舉例子:
來自於org.springframework.beans.factory.config的DeprecatedBeanWarner,其作用是通過Deprecated註解來過濾警告我們有些類已經過期了,請注意
我們看看其實現:
首先Deprecated的功能簡單,很容易一目瞭然,主要是postProcessBeanFactory和logDeprecatedBean這兩個方法
首先先檢查log是否啓用,如果啓用,那麼通過beanFactory獲取所有beanDefinitionNames,然後遍歷,這裏注意isFactoryBean這個方法如果是factoryBean的話,需要通過"&"+beanName的方法查找class(對於factorybean我們會再找一篇機會重點分析一下,畢竟是spring ioc幾個關鍵組成),找到class後,看是否有Deprecated這個註解,如果有的話那麼就進入logDeprecatedBean方法
這個方法就更簡單了,將bean的信息打印出來,這樣就完成了警告
以上就是spring內部對beanFactoryPostProcessor的簡單應用,至此我們對beanFactory相信已經有了很深的印象,步步前行,紮實基礎!!!