spring依賴注入的實現原理

Spring 從核心而言,是一個DI 容器,其設計哲學是提供一種無侵入式的高擴展性框架。即無需代
碼中涉及Spring專有類,即可將其納入Spring容器進行管理。
作爲對比,EJB則是一種高度侵入性的框架規範,它制定了衆多的接口和編碼規範,要求實現者必須
遵從。侵入性的後果就是,一旦系統基於侵入性框架設計開發,那麼之後任何脫離這個框架的企圖都將付
出極大的代價。
爲了避免這種情況,實現無侵入性的目標。Spring 大量引入了Java 的Reflection機制,通過動態
調用的方式避免硬編碼方式的約束,並在此基礎上建立了其核心組件BeanFactory,以此作爲其依賴注入
機制的實現基礎。
org.springframework.beans包中包括了這些核心組件的實現類,核心中的核心爲BeanWrapper
和BeanFactory類。這兩個類從技術角度而言並不複雜,但對於Spring 框架而言,卻是關鍵所在。

Bean Wrapper
從Quick Start的例子中可以看到,所謂依賴注入,即在運行期由容器將依賴關係注入到組件之中。
講的通俗點,就是在運行期,由Spring根據配置文件,將其他對象的引用通過組件的提供的setter方法進
行設定。
我們知道,如果動態設置一個對象屬性,可以藉助Java的Reflection機制完成:
Class cls = Class.forName("net.xiaxin.beans.User");
Method mtd = cls.getMethod("setName",new Class[]{String.class});
Object obj = (Object)cls.newInstance();
mtd.invoke(obj,new Object[]{"Erica"});
return obj;

上面我們通過動態加載了User類,並通過Reflection調用了User.setName方法設置其name屬性。
對於這裏的例子而言,出於簡潔,我們將類名和方法名都以常量的方式硬編碼。假設這些常量都是通過配
置文件讀入,那我們就實現了一個最簡單的BeanWrapper。這個BeanWrapper的功能很簡單,提供一個
設置JavaBean屬性的通用方法(Apache BeanUtils 類庫中提供了大量針對Bean的輔助工具,如果有興
趣可以下載一份源碼加以研讀)。
Spring BeanWrapper基於同樣的原理,提供了一個更加完善的實現。
看看如何通過Spring BeanWrapper操作一個JavaBean:
Object obj = Class.forName("net.xiaxin.beans.User").newInstance();
BeanWrapper bw = new BeanWrapperImpl(obj);
bw.setPropertyValue("name", "Erica");
System.out.println("User name=>"+bw.getPropertyValue("name"));

對比之前的代碼,相信大家已經知道BeanWrapper的實現原理。
誠然,通過這樣的方式設定Java Bean屬性實在繁瑣,但它卻提供了一個通用的屬性設定機制,而這
樣的機制,也正是Spring依賴注入機制所依賴的基礎。
通過BeanWrapper,我們可以無需在編碼時就指定JavaBean的實現類和屬性值,通過在配置文件
加以設定,就可以在運行期動態創建對象並設定其屬性(依賴關係)。
上面的代碼中,我們僅僅指定了需要設置的屬性名“name”,運行期,BeanWrapper將根據Java
Bean規範,動態調用對象的“setName”方法進行屬性設定。屬性名可包含層次,如對於屬性名“address.zipcode”,BeanWrapper會調用“getAddress().setZipcode”方法。

Bean Factory
Bean Factory,顧名思義,負責創建並維護Bean實例。
Bean Factory負責根據配置文件創建Bean實例,可以配置的項目有:
1. Bean屬性值及依賴關係(對其他Bean的引用)
2. Bean創建模式(是否Singleton模式,即是否只針對指定類維持全局唯一的實例)
3. Bean初始化和銷燬方法
4. Bean的依賴關係
下面是一個較爲完整的Bean配置示例:
<beans>
<description>Spring Bean Configuration Sample</description>
<bean
id="TheAction" ⑴
class="net.xiaxin.spring.qs.UpperAction" ⑵
singleton="true" ⑶
init-method="init" ⑷
destroy-method="cleanup" ⑸
depends-on="ActionManager" ⑹
>
<property name="message">
<value>HeLLo</value> ⑺
</property>
<property name="desc">
<null/>
</property>
<property name="dataSource">
<ref local="dataSource"/> ⑻
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/sample</value>
</property>
</bean>
</beans>

下面的代碼演示瞭如何通過BeanFactory獲取Bean實例:
InputStream is = new FileInputStream("bean.xml");
XmlBeanFactory factory = new XmlBeanFactory(is);
Action action = (Action) factory.getBean("TheAction");
此時我們獲得的Action實例,由BeanFactory進行加載,並根據配置文件進行了初始化和屬性設定。
聯合上面關於BeanWrapper的內容,我們可以看到,BeanWrapper實現了針對單個Bean的屬性設
定操作。而BeanFactory則是針對多個Bean的管理容器,根據給定的配置文件,BeanFactory從中讀取
類名、屬性名/值,然後通過Reflection機制進行Bean加載和屬性設定。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章