作者:江南白衣 

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

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

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

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

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

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

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

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


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

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

只不過(guò)當(dāng)年對(duì)這類factoryBean比較麻木不仁,不問(wèn)原理的照搬照用了。

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

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

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


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

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