(點選上方公眾號,可快速關註)
來源:隨風溜達的嚮日葵@ ,
www.chkui.com/article/spring/spring_core_ioc_extension_points
《 Spring核心 : IOC 處理器擴充套件 》介紹了非侵入式的框架的概念以及IOC的功能擴充套件點之一——BeanPostProcessor,我們接下來的內容繼續說明IoC更多的擴充套件方法。
BeanFactoryPostProcessor
BeanFactoryPostProcessor是針對整個容器的後置處理器。他的使用也非常簡單,只要向容器中新增一個繼承BeanFactoryPostProcessor的Bean即可。
如何使用
繼承了BeanFactoryPostProcessor介面的類PostProcessors:
package chkui.springcore.example.xml.beanfactorypostprocessor;
public class PostProcessors implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//DO
}
}
然後再向容器中新增這個Bean就增加了一個BeanFactoryPostProcessor。
BeanFactoryPostProcessor主要用於處理容器相關的內容,他被觸發時機是在IoC容器載入完各種配置後,還沒執行Bean的初始化之前。這個時候除了PostProcessors這個Bean,其他任何Bean都沒有被建立。 所以在BeanFactoryPostProcessor處理Bean是不合適的,Bean應該要到BeanPostProcessor中去處理,2者的區別就是前者面向容器,後者面向Bean。接下來將透過一個詳細例子來說明BeanFactoryPostProcessor和BeanPostProcessor的區別以及使用方式。期間還會介紹BeanDefinitio相關的內容。
BeanFactoryPostProcessor與BeanPostProcessor使用
文中僅僅是示例程式碼,無法執行,原始碼在https://gitee.com/chkui-com/spring-core-sample,如需下載請自行clone
建造者樣式
下麵將會透過一個例子介紹2者的使用方式和使用場景。例子使用建造者樣式模擬組裝一臺個人電腦,分為一下3步:
-
容器啟動之後,會將電腦的所有“配件”(Cpu、Graphics、Ram)都新增到容器中。
-
在PostProcessorS實現BeanFactoryPostProcessor介面,它的功能是向容器新增一個Pc物件。
-
在PostProcessor實現BeanPostProcessor介面。他的工作是組裝電腦——每一個Bean都會檢查域上的@Autowired註解,並註入對應的部件,部件也會標記自己所屬的電腦。
下麵是XML配置檔案,它負責將Cpu、顯示卡、記憶體等電腦常用品牌的部件放置到容器中等待組裝。此外它還添加了PostProcessorS和PostProcessor兩個後置處理器用於裝載電腦。
下麵是一個Cpu物件的結構,他標記了品牌和所屬電腦。Graphics和Ram的結構和它一模一樣。
package chkui.springcore.example.xml.beanfactorypostprocessor.bean;
public class Cpu {
private String brand;
@Autowired
private Pc belong;
}
註意這裡的@Autowired註解,我們的配置檔案並沒有開啟Spring的自動裝配功能,我們將在PostProcessor實現自動裝配。
PostProcessorS的作用是向容器動態新增一個之前未定義的Bean——Pc。
package chkui.springcore.example.xml.beanfactorypostprocessor;
public class PostProcessors implements BeanFactoryPostProcessor{
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
//獲取容器的註冊介面
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
//新建一個BeanDefinition用於動態裝配Bean
GenericBeanDefinition defininition = new GenericBeanDefinition();
//設定要新增的類
defininition.setBeanClass(Pc.class);
//註冊BeanDefinition
registry.registerBeanDefinition(“postBean”, defininition);
}
}
如果看過 Ioc結構介紹的這篇文章,你就會知道BeanFactory經過層層派生,實際上大部分介面都在一個類實現——DefaultListableBeanFactory,它除了實現ConfigurableListableBeanFactory介面,還實現了BeanDefinitionRegistry介面。BeanDefinitionRegistry提供了BeanDefinition的管理功能。
https://www.chkui.com/article/spring/spring_core_context_and_ioc
BeanDefinition與配接器樣式
在上面的程式碼中出現了BeanDefinition介面,這裡就順道說一說這個有趣的小玩意。關於他如何使用Spring的官網並沒有太詳細的介紹(至少我沒找到),網上倒是有各路大神的部落格在解讀他的原始碼,不過程式碼只是表象,要理解他的整套設計思路才能提升。
關於BeanDefinition的使用樣式,官網將其稱呼為configuration metadata,直譯過來叫“配置元資料”。 他的作用有點類似於Context分層應用的效果(見Spring核心——背景關係與IoC 關於 ApplicationContext的說明),目的就是將Bean的配置和初始化工作分成2個互不幹擾的部分。
我們知道 Spring現在支援各種各樣的方式來新增Bean,比如在XML配置檔案中使用
為瞭解決這個問題Spring的大神們引入了配接器樣式——IoC容器只接受BeanDefinition介面,IoC如何初始化一個Bean是僅僅是看BeanDefinition裡的資訊。而各種配置方式都有自己的配接器,所有的配接器都會根據他所需要處理的內容來生成一個BeanDefinition的實現類。這樣,如果新增一個新的配置方式,增加一個配接器就可以搞定。
所以,我們也可以利用BeanDefinitionRegistry介面向容器新增一個BeanDefinition,進而在隨後的執行過程中IoC容器會根據 這個BeanDefinition建立一個對應的Bean。
BeanPostProcessor
前面已經提到,BeanFactoryPostProcessor用於處理容器級別的問題,而BeanPostProcessor用來處理每一個Bean。我們前面已經用BeanFactoryPostProcessor向容器添加了一個Pc物件的Bean,接下來我們在BeanPostProcessor中處理每一個Bean的自動註入註解。
package chkui.springcore.example.xml.beanfactorypostprocessor;
public class PostProcessor implements BeanPostProcessor, BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return autowiredImplement(bean);
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
//自定義實現autowired功能
private Object autowiredImplement(final Object bean) {
for(Field field : bean.getClass().getDeclaredFields()) {
Autowired value = field.getAnnotation(Autowired.class);
if(null != value) {
Object obj = beanFactory.getBean(field.getType());
field.setAccessible(true);
field.set(bean, obj);
}
}
return bean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory)beanFactory;
}
}
這裡的PostProcessor實現BeanFactoryAware介面來獲取 BeanFactory。自動註入的處理邏輯都在autowiredImplement方法中,它會掃描Bean的每一個域檢查是否有@Autowired註解,如果有則根據這個域的Class型別到BeanFactory去獲取對應的Bean,然後反射註入。
最後我們建立一個ApplicationContext來執行他們:
public class SampleApp {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“xml/beanfactorypostprocessor/config.xml”);
Pc pc = context.getBean(Pc.class);
/**
Pc Info: Graphics=Nvdia, Cpu=Amd, Ram=Kingston]
*/
System.out.println(pc);
}
}
本文介紹了BeanFactoryPostProcessor和BeanPostProcessor的使用方式,以及IoC容易是如何透過BeanDefinition裝載各種配置的。後續還會持續介紹Spring IoC容器的各種功能擴充套件點。
【關於投稿】
如果大家有原創好文投稿,請直接給公號傳送留言。
① 留言格式:
【投稿】+《 文章標題》+ 文章連結
② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/
③ 最後請附上您的個人簡介哈~
看完本文有收穫?請轉發分享給更多人
關註「ImportNew」,提升Java技能