摘要:討論了POJO即純JAVA簡單舊式對象與持久對象即PO的區別和聯系,詳細介紹了在Spring和EJB3.0框架中依賴注入方式的實現機制,并由此比較了兩種框架開發應用程序的過程中應用服務的方式及其復雜性。
關鍵詞:POJO;PO;Spring;EJB3.0;依賴注入
中圖分類號:TP311文獻標識碼:A 文章編號:1009-3044(2008)26-1617-03
The application and realization of DI in Spring Framework and EJB3.0 environment
LI Fa-ying
(Department of computer science,Xiangnan University, Chenzhou 423000, China)
Abstract: District and relation of pojo and po are dicussed. Realization mecanism of DI method in the Spring and EJB3.0 framework is introduced. Complexicities of both DI method are analized in the two frameworks.
Key words: POJO; PO; spring; EJB3.0; dependency injection
1 引言
隨著Internet的廣泛應用,分布式環境下應用程序的開發越來越關注提高程序的松散耦合性能。基于J2EE的MVC模式開發框架提出了分層概念,在不同層次實現應用程序的不同功能。在業務邏輯層,由于涉及到根據不同的業務需求必須對數據進行處理,根據對數據處理方式的不同以及處理數據所需要的服務對象的引入方式,在Spring和EJB3.0兩種框架中實現依賴注入的方式不同。Spring和EJB3.0分別使用XML文件和增加注釋的方式來實現DI,最后達到應用系統松散藕合的目的。
2 DI概述
DI(Dependency Injection),中文譯名是依賴注入,在應用程序實現時,可以把一個對象注入一個類,而不是直接實例化一個類的對象。從組件的可重用性和組件的互操作性角度來看,這種依賴注入機制大大提高系統的松散耦合性能,減小了由于系統組件的增加帶來的系統復雜性和系統性能的降低。
依賴注入(DI)是一項編程技術,在一定情況下也被稱為控制倒轉或是IOC。從技術上來講,依賴注入是特指有限范圍內的特殊形式的控制倒轉(Inersion of Control,IOC)。
依賴注入是指由特定的類提供一個可供運行的部分給正在運行的另一個類執行,前者被稱為注入類。通常情況下會有多個不一的注入類存在,或是其子類。主類抽象出一系列通用代碼供實現所需并且在面對特定需求時將這些代碼分派給之前所提到的注入類。
DI模式是實現松散耦合的應用程序最好的方法之一。相對于傳統的基于JNDI的依賴查找或容器回調更易于使用。使用DI時,框架組件充當建立服務對象的對象工廠,并根據運行時配置,把這些服務對象注入應用程序POJO中,從應用程序開發者的角度來看,當客戶端POJO需要使用某種服務對象時,它們會自動地獲取該對象。DI模式可以延緩接口的實現,根據需要實現。圖1說明了采用DI前后的依賴關系變化。
使用DI之前(如圖1左邊部分所示),Spring中實現業務邏輯所需要的服務是通過編程接口實現的,將服務集成代碼作為編程接口的一部分,應用開發者可以根據需要選擇集成服務。在WEB應用實現時使用DI,將應用程序中所需要的服務對象作為一個獨立的組件存儲,組件的代碼并不是在接口中實現,在應用程序執行過程中,如果需要某種服務,再以DI方式使用服務對象。Spring最普遍的使用方式是把Tomcat和Hibernate結合起來提供簡單的數據庫驅動WEB應用程序。在這種方式下,Spring自身提供事務服務,Hibernate提供持久服務。
通過Hibernate實現對數據庫的直接訪問,在客戶機代碼中要訪問數據庫變得易于操作,只需要編寫一個XML配置文件,并建立一個對象—關系映射,而不需要為類和數據庫表的關聯編寫額外的代碼。
EJB3應用程序開發框架在應用程序開發者的業務邏輯層可以提供所有的服務,并且這些服務都是預先包裝好的,如資源緩沖池服務,消息隊列服務和群集服務等。
從系統的資源消耗角度看,Spring與EJB3解決方案都是重量級的解決方案。在應用程序開發過程中,很容易將許多無用的服務對象融合到應用中,使得應用程序代碼量增加并影響應用程序的運行效率。
3 Spring與EJB3依賴注入的實現
POJO(Plain Old Java Object)簡單舊式JAVA對象就是普通意義上的JavaBeans,該類對象又可以稱為DATA對象,POJO的特點是:可以聲明Private屬性,也可以聲明get和set方法,但一般不可以聲明業務方法。如以下代碼段:
public class User {
private long id;
private String name;
public void setId(long id) {
this.id = id; }
public void setName(String name) {
this.name=name; }
public long getId() {
return id; }
public String getName() {
return name; } }
在上述代碼段,POJO對象是USER對象,其中聲明了兩個private類型的屬性,屬性名分別為id和name,并聲明了兩get方法和兩個set方法,分別獲取用戶的ID和用戶名,設置用戶的ID和用戶名。
3.1 POJO與PO的區別
POJO即簡單舊式JAVA對象,PO(PersisentObject),中文名為持久對象,一個持久對象除了具備POJO的全部特性外,還應該聲明維護數據表記錄的方法,即PO應包含有用來管理數據庫實體狀態的屬性和方法。POJO與PO有以下三個方面的區別:
1) 創建方式不同:POJO由NEW創建,而PO通過insert數據庫創建;
2) 銷毀方式不同:POJO由GC回收,而PO由delete操作刪除;
3) 存在周期的差異:POJO只要不被GC回收,總是存在,而PO與數據庫連接有關,當某一個數據連接關閉后,PO也就被銷毀了。
Hibernate對POJO的操作實際上是在運行期將POJO轉化為PO,這種轉化方法有點類似于JSP程序的運行,只是JSP程序是在編譯期間轉化為Servlet。也就是說,程序員直接接觸的是POJO對象,實際執行代碼時轉化為PO持久對象,換句話說,PO持久對象對程序是透明的。
3.2 DI機制的實現
Spring和EJB3都給DI模式提供了廣泛的支持,但是它們在實現機制上有所差異。Spring支持普通的、復雜的并基于XML配置文件的DI API;而EJB3則通過簡單的注釋支持大多數通用服務對象如EJB和上下文關系對象以及JNDI對象的注入操作。
4 Spring和EJB3框架依賴注入的實現機制
4.1 EJB3框架依賴注入的實現機制
EJB3的DI注釋非常簡潔,易于使用。通常有三種注入方法。
1) 將字段變量直接注入。使用@Resource標簽注入大多數通用服務對象和JNDI對象。以下代碼是EJB3的依賴注入實現代碼:
public class FooDao {
@Resource (name=\"DefaultDS\")
DataSource myDb;// 使用 myDb 獲取數據庫的JDBC連接}
通過上述代碼,可以將JNDI中的服務器默認的DataSource對象注入POJO的一個字段變量中。DefaultDS是JNDI用于表示DataSource的名稱。在第一次使用myDb變量之前,會把正確的值自動地賦給它。
2) 使用@Resource標簽,通過設置方法(setter方法)來注入對象。代碼如下所示:
@Resource
public void setSessionContext (SessionContext ctx) {
sessionCtx = ctx; }
在上述代碼中,通過@Resource標簽注入了一個對話上下文關系(context)對象。應用程序沒有顯式調用設置方法,一般說,設置方法在被應用程序的其他任何方法調用之前,會先被容器調用。
3) 通過專用的注入注釋實現。在EJB3中常用的專用注釋有:
@ejb注釋用于注入EJB stub;
@PersistenceContext注釋用于注入EntityManager對象,該對象為EJB3實體BEAN處理數據庫訪問;假如要向一個有狀態的會話BEAN注入EntityManager對象,代碼如下:
@Stateful
public class FooBean implements Foo, Serializable {
@PersistenceContext(
type=PersistenceContextType.EXTENDED}
protected EntityManager em;
public Foo getFoo (Integer id) {
return (Foo) em.find(Foo.class, id);}}
在上述代碼中,@PersistenceContext注釋的type屬性指明被注入的EntityManager擁有擴展的事務上下文關系,它不會自動地與JTA事務管理器一起提交,該注入方式可以用于那些在一個對話中跨越多個線程的應用程序事務。
4.2 Spring框架的依賴注入實現機制
在Spring中,實現注入的基本步驟:
1) 為POJO服務對象定義一個設置方法或帶參數的構造函數。
public class FooDao {
HibernateTemplate hibernateTemplate;
public void setHibernateTemplate (HibernateTemplate ht) {
hibernateTemplate = ht;}
// 使用 Hibernate 模板訪問數據
public Foo getFoo (Integer id) {
return (Foo) hibernateTemplate.load (Foo.class, id);}}
2) 獲取服務對象并實現捆綁操作。
對于上述代碼,為了實現容器在運行時通過XML元素鏈獲取服務對象,必須把數據源捆綁到Hibernate對話工廠,將對話捆綁到Hibernate模板對象后,將模板對象捆綁到應用程序POJO的XML元素。具體代碼如下:
<bean id=\"dataSource\"
class=\"org.springframework
.jndi.JndiObjectFactoryBean\">
<property name=\"jndiname\">
<value>java:comp/env/jdbc/MyDataSource</value>
</property>
</bean>
<bean id=\"sessionFactory\"
class=\"org.springframework.orm
.hibernate.LocalSessionFactoryBean\">
<property name=\"dataSource\">
<ref bean=\"dataSource\"/>
</property>
</bean>
<bean id=\"hibernateTemplate\"
class=\"org.springframework.orm
.hibernate.HibernateTemplate\">
<property name=\"sessionFactory\">
<ref bean=\"sessionFactory\"/>
</property>
</bean>
<bean id=\"fooDao\" class=\"FooDao\">
<property name=\"hibernateTemplate\">
<ref bean=\"hibernateTemplate\"/>
</property>
</bean>
<!-- The hibernateTemplate can be injected
into more DAO objects -->
由此可見,在Spring中依賴注入的實現是基于XML文檔的,相對于EJB3來說,語言法更為復雜,但功能強大得多。可以實現把任何POJO注入另一個POJO。
5 結束語
Spring和EJB3的目標都是為松散耦合的POJO提供企業級服務,他們實現依賴注入的方式不同。使用EJB3時,基于標準的方法、注釋的大量使用以及與應用程序服務器的緊密集成形成了強大的廠商無關性和開發者的高效性。使用Spring的時候,使用集中的XML配置文件,允許開發者構造更加靈活的應用程序,并在同一時刻可以使用多個應用服務。
參考文獻:
[1] 孫衛琴.精通Structs基于MVC的Java Web設計與開發[M].北京:電子工業出版社,2004:2002-210.
[2] Sun Microsystems Inc.Simplified guide to the Java 2 platform enterprise edition [EB/OL].http://java.sun.com/J2EE/reference/whitepapers/j2ee_guide.pdf.
[3] Apache Software Foundation. User and developer guides[EB/OL].http://struts.apache.oorg//struts-doo-1.2.8/index.html.
[4] Hibernate reference documentation[EB/OL].http://www.hibernate.org/lib_docs/reference/zh-cn/pdf/hibernate_reference.pdf.