全文共 1685 個字git
上一篇文章介紹了非侵入式的框架的概念以及IOC的功能擴展點之一——BeanPostProcessor,咱們接下來的內容繼續說明IoC更多的擴展方法。spring
BeanFactoryPostProcessor是針對整個容器的後置處理器。他的使用也很是簡單,只要向容器中添加一個繼承BeanFactoryPostProcessor的Bean便可。框架
繼承了BeanFactoryPostProcessor接口的類PostProcessors:ide
package chkui.springcore.example.xml.beanfactorypostprocessor; public class PostProcessors implements BeanFactoryPostProcessor{ @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { //DO } }
而後再向容器中添加這個Bean就增長了一個BeanFactoryPostProcessor。post
<?xml version="1.0" encoding="UTF-8"?> <!-- xml.beanfactorypostprocessor --> <beans> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.PostProcessors" /> </beans>
BeanFactoryPostProcessor主要用於處理容器相關的內容,他被觸發時機是在IoC容器加載完各類配置後,還沒執行Bean的初始化以前。這個時候除了PostProcessors這個Bean,其餘任何Bean都沒有被建立。 因此在BeanFactoryPostProcessor處理Bean是不合適的,Bean應該要到BeanPostProcessor中去處理,2者的區別就是前者面向容器,後者面向Bean。接下來將經過一個詳細例子來講明BeanFactoryPostProcessor和BeanPostProcessor的區別以及使用方式。期間還會介紹BeanDefinitio相關的內容。ui
(文中僅僅是示例代碼,沒法運行,源碼在https://gitee.com/chkui-com/spring-core-sample,如需下載請自行clone)this
下面將會經過一個例子介紹2者的使用方式和使用場景。例子使用建造者模式模擬組裝一臺我的電腦,分爲一下3步:spa
下面是XML配置文件,它負責將Cpu、顯卡、內存等電腦經常使用品牌的部件放置到容器中等待組裝。此外它還添加了PostProcessorS和PostProcessor兩個後置處理器用於裝載電腦。.net
<beans> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.bean.Cpu"> <property name="brand" value="Amd"/> </bean> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.bean.Graphics"> <property name="brand" value="Nvdia"/> </bean> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.bean.Ram"> <property name="brand" value="Kingston"/> </bean> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.PostProcessor" /> <bean class="chkui.springcore.example.xml.beanfactorypostprocessor.PostProcessors" /> </beans>
下面是一個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的管理功能。
在上面的代碼中出現了BeanDefinition接口,這裏就順道說一說這個有趣的小玩意。關於他如何使用Spring的官網並無太詳細的介紹(至少我沒找到),網上卻是有各路大神的博客在解讀他的源碼,不過代碼只是表象,要理解他的整套設計思路才能提高。
關於BeanDefinition的使用模式,官網將其稱呼爲configuration metadata,直譯過來叫「配置元數據」。 他的做用有點相似於Context分層應用的效果(見Spring核心——上下文與IoC 關於 ApplicationContext的說明),目的就是將Bean的配置和初始化工做分紅2個互不干擾的部分。
咱們知道 Spring如今支持各類各樣的方式來添加Bean,好比在XML配置文件中使用<bean>標籤、使用@Component以及他的派生類註解、能夠在@Configuration類中生成、甚至還能夠經過RMI實現遠程配置等等。若是全部的這些配置來源直接和IoC容器產生關係生成Bean,那麼耦合度、代碼複雜度會愈來愈高,並且之後指不定何時又會加入什麼新的配置方式。
爲了解決這個問題Spring的大神們引入了適配器模式——IoC容器只接受BeanDefinition接口,IoC如何初始化一個Bean是僅僅是看BeanDefinition裏的信息。而各類配置方式都有本身的適配器,全部的適配器都會根據他所須要處理的內容來生成一個BeanDefinition的實現類。這樣,若是新增一個新的配置方式,增長一個適配器就能夠搞定。
因此,咱們也能夠利用BeanDefinitionRegistry接口向容器添加一個BeanDefinition,進而在隨後的執行過程當中IoC容器會根據 這個BeanDefinition建立一個對應的Bean。
前面已經提到,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容器的各類功能擴展點。