作者:江南白衣 

              擴展Spring系列(1)--Spring 的微內(nèi)核與FactoryBean擴展機制

DreamHead在《思考微內(nèi)核》十分激賞 Spring的微內(nèi)核與擴展機制:
“Spring的微內(nèi)核在哪里呢?便是DI容器。而通過FactoryBean,我們可以定制自己的組件組裝過程,對一個普通的JavaBean做手腳,像Spring AOP中常用的ProxyFactoryBean做的那樣。如此,我們就不必把所有功能都做到Spring的DI容器中去,而是以一個FactoryBean來對DI容器的功能進行擴展。除了Spring自身之外,現(xiàn)在已經(jīng)有一些項目開始利用這個特性擴展Spring,比如,Acegi Security和Spring Modules。”

 這確是框架容器界應(yīng)該貫徹的范式,微內(nèi)核提供最少的功能,而由擴展接口去增強框架的能力。下面看看Spring怎么設(shè)計,明白之后就可以開始為Spring捐獻精力了:)

1、微內(nèi)核的功能
1.1 DI(依賴注入)與Singleton管理
      利用POJO setter的DI機制,估計每位同學(xué)隨手都能寫一個簡單版本,不多說了。
      Singleton管理說白了就是先到一個map中按id找找看有沒有已存在的實例。

1.2 BeanName與BeanFactory注入
      除了DI注入的屬性,微內(nèi)核還有什么能賣給POJO呢?就是Bean在xml 定義里的id和BeanFactory自己了。
      賣的機制是讓POJO 實現(xiàn) BeanNameAware和BeanFactoryAware接口。BeanFactory用 if(pojo instance of BeanFactoryAware)判斷到POJO需要注入BeanFactory,就調(diào)用setBeanFactory(this)將自己注入。

      這種框架中基于接口的注入和調(diào)用機制在Java下挺標準的,Spring的功能多是基于這種模式提供。遺憾就是Java不支持多重繼承,作為替代的接口里不能提供默認的實現(xiàn),導(dǎo)致每一個Pojo都要很無聊的實現(xiàn)一遍setBeanFactory()。

1.3 DI后的初始化函數(shù)調(diào)用
      比如屬性A,B注入之后,需要同時根據(jù)A和B來對A,B進行加工或者裝配一個內(nèi)部屬性C,這樣就需要在所有屬性注入后再跑一個init()函數(shù)。
      Spring提供兩種方式,一種是和上面的原理一樣,實現(xiàn)InitializingBean接口的afterPropertiesSet()函數(shù)供Spring調(diào)用。
      一種是在xml定義文件里面自行定義init函數(shù)名。
      懶得每次在xml文件里定義的就采用第1種方式,不想與spring耦合的pojo就采用第2種方式。本來就是為了擴展Spring而存在的FactoryBean多采用第一種。

   所謂微內(nèi)核,就是僅提供以上三種功能的DI容器。
   但作為輕量級容器,還需要以下兩種方式,向容器內(nèi)的POJO 附加各種服務(wù)。


2.FactoryBean擴展機制
Spring的AOP、ORM、事務(wù)管理、JMX、Quartz、Remoting、Freemarker、Velocity,都靠FacotryBean的擴展,F(xiàn)acotryBean幾乎遍布地上:
<bean id="sessionFactory"
class
="org.springframework.orm.hibernate3.LocalSessionFactoryBean"/>

<bean id="baseDAOService"
class
="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"/>

只不過當年對這類factoryBean比較麻木不仁,不問原理的照搬照用了。

不過這原理說出來也好簡單,所有FactoryBean 實現(xiàn)FactoryBean接口的getObject()函數(shù)。Spring容器getBean(id)時見到bean的定義是普通class時,就會構(gòu)造該class的實例來獲得bean,而如果發(fā)現(xiàn)是FacotryBean接口的實例時,就通過調(diào)用它的getObject()函數(shù)來獲得bean,僅此而以.......可見,很重要的思想,可以用很簡單的設(shè)計來實現(xiàn)。

考察一個典型的FactoryBean:
    一般會有兩個變量,三個接口:
    一個setter函數(shù)注入需要改裝的pojo,一個內(nèi)部變量保持裝配后的對象returnOjbect。
    implements三個接口 :FactoryBean,InitializingBean和BeanFactoryAware 。
    各接口的意義之前都講過了。factoryBean會在afterPropertiesSet()里把pojo改裝成returnObject,需要用到beanfactory進行天馬行空的動作時就靠BeanFactoryAware注入。最后在getObject()里把returnObject返回。

Rod說:IoC principles, combined with the factory bean, afford a powerful means to abstract the act of obtaining or accessing services and resources

3. Bean Post-Processor擴展機制
     如果說FactoryBean 是一種Factory、Wrapper式的擴展,Bean Post-Processor就是另一種AOP、visitor式的機制,所以也多用于spring的AOP架構(gòu)。
      Post-Processor的原理就是BeanFactory在前文里的調(diào)用afterPropertiesSet()/init-method前后,調(diào)用在工廠里注冊了的post-processor的postProcessBeforeInitialization()和postProcessAfterInitialization()。
      那怎么注冊登記呢?又分請不請禮儀公司兩類。如果是ApplicationContext,你把繼承BeanPostProcessor 的bean往xml里一擱就行了,application context自會打理。如果是BeanFacotry,就要顯式的注冊,代碼大概像:
     
XmlBeanFactory factory = new XmlBeanFactory("C:/beans.xml"); 
BeanPostLogger logger 
= new BeanPostLogger(); 
factory.addBeanPostProcessor(logger);


Rod說:"Post-processors add the ability to customize bean and container behavior in a flexible, externalized fashion. "
對比Factory Bean那段,可見兩種機制在他心目中的不同作用。

系列文章:
Spring 的微內(nèi)核與FactoryBean擴展機制
擴展Spring(2)--Spring對各種數(shù)據(jù)訪問框架的集成機制