Spring 與 EJB 比較

 

在開源領域,Spring開源框架已成爲企業應用開發中使用最多的開源框架。Spring框架的優秀不但表現在其優雅的底層設計、使用方便快捷、面向工作實踐、超強粘合能力等方面,另外一個不可忽視的方面是Spring擁有一個世界一流且活躍的技術開發團隊。隨着Spring的流行,於是,大家開始對比Spring與另一種流行的框架組件EJB。目前網上關於SpringEJB的爭論頗多。很多架構師認爲Spring會替代EJB,也有架構師認爲Spring是開源的東西,是不成熟且無法和商業解決方案媲美的框架,因此,在SpringEJB的對比過程,有若干對Spring的片面認識。而本文希望通過對這些誤區的分析,給Spring一個原本的認識與理解。

一、        前言

EJB 3.0框架是JCP定義的並且被所有主流J2EE提供商支持的標準框架。EJB 3.0規範的發佈版本目前已經有開源的和商業的實現,如JBOSSORACLEEJB 3.0大量使用了JAVA註解(Java annotations,是JDK1.5提供的新功能)。

EJB最初的設計思想考慮的是爲分佈式的應用服務的,分佈式是針對大型應用構造的跨平臺的協作計算,EJB最初的目的就是爲這種計算服務的。但是軟件發展到目前爲止,大多數應用不需要採用分佈式的解決方案,因此用EJB顯得太臃腫了。Spring的出現恰恰爲了解決這個問題。舉個例子來說,EJB就是導彈,專門設計爲打高空飛機。但是現在發現飛機不多。於是將它用來對付步兵,這個實在太糟糕了。這個時候有人發明了狙擊步槍(Spring),發現對付步兵太好用了。

Spring框架是一個廣受歡迎的但是非標準的開源框架。它主要由Interface21公司開發和控制。Spring框架的體系結構是基於注射依賴(DI)模式。Spring框架使用了大量的XML配置文件,它可以獨立應用,或者在現有的應用服務器上工作。

這兩個框架有着一個共同的核心設計理念:它們的目標是爲鬆耦合的POJO類提供中間件服務。框架通過在運行時截取執行環境,或將服務對象注射給POJO類的方式,將應用服務和POJO連接起來。POJO類本身並不關注如何連接,而且也很少依賴於框架。

這樣,開發者可以將注意力集中在業務邏輯上,可以對他們的POJO類進行與框架無關的單元測試。並且,由於POJO類不需要繼承框架的類或實現框架提供的接口,開發者可以在更加靈活性的基礎上構建繼承體系,和搭建應用。

儘管有着共同的理念,但這兩個框架採取了不同的方式來提供POJO服務。由於已經出了大量的比較SpringEJB3.0的文章。但發現,隨着Spring的發展,其中對Spring的認識難免有失偏頗的地方,因此,本文將考察它們之間幾個關鍵的認識上的誤區進行分析。

二、        SpringXML VS EJB的註釋

從應用開發者的角度來看,Spring的編程接口主要基於XML配置文件,而EJB 3.0則大量的使用了JAVA註解。XML文件可以表達複雜的關係,但是它們更加冗長而且不健壯。註解的方式很簡單明瞭,但是很難去表達複雜的或者繼承性的結構。

由於EJB 3.0Spring相互學習了很多特性,所以,它們都在某種層次上支持XML和註釋。例如,EJB 3.0中可以應用XML配置文件作爲一個選擇性的機制,用來改變註釋的默認行爲。註釋也可以用來配置一些Spring服務。

Spring 2中,採用了@PersistenceContext註釋的方式來整合JPAJava 持久性 API),從而實現了EntityManager對象的注入,同時通過@Transactional實現聲明式事務管理。Spring 2利用註釋來支持AspectJ(一種面向切面的框架,它擴展了Java語言),如@Aspect@Before@After@Around等等註釋。Spring 2中,使用@Repository註釋,可以直接操作JPAHibernate API,而不需要使用Spring模板。

Spring的元數據模型非常的靈活的,因此在Spring中可以快速的建立起基於註釋的元數據模型。而從最近發佈的Spring 2.5看來,事實上也是這樣。Spring 2.5全面支持JSR-250註釋(JSR-250技術規範主要涉及J2SEJ2EE平臺上開發普通語義概念的標註,提供一種獨立技術),如@Resource@PostConstruct@PreDestroy@WebServiceRef@EJB

特別值得一提的是@Resource,最早是爲了在EJB 3使用Spring的依賴注入功能。但如今其功能已經擴展了,不但支持像JNDI的查找,還可以注入任何的Spring管理對象。這就把Spring的優勢(Spring支持任何對象的依賴注入)和EJB的優勢(使用註釋代替XML)充分的結合起來了。

Spring 2.5中提供了完整的基於註釋的依賴注入模型,如@Autowired@Qualifier註釋。用戶通過@Autowired註解來對Bean的屬性變量、屬性Setter方法以及構造函數進行標註,配合AutowiredAnnotationBeanPostProcessor完成對Bean的自動裝配。

@Component註釋爲用戶自定義原形進行了擴展。Spring可以自動的檢測到註釋的組件。例如下面的代碼

<context:component-scan base-package="org.springframework.samples.petclinic.web" />

Web控制器不需要額外的XML配置,因爲使用了基於註釋的依賴注入以及基於註釋的請求映射。Web控制器通過如下的代碼進行管理:

@Controller
public class ClinicController {

private final Clinic clinic;

@Autowired
public ClinicController(Clinic clinic) {
this.clinic = clinic;
}

三、        EJB使用JPASpring使用Hibernate

很多人都認爲,在EJB 3中通過使用@PersistenceContext註釋提供的entityManager對象來獲得JPA的數據訪問,而在Spring中,通過對SessionFactory對象的注入獲得Hibernate數據訪問。從而自然而然地認中,EJB使用JPA來操作數據對象,而Spring使用Hibernate來操作數據對象。

作爲EJB3.0的一部分,JPA是一個好東西。其簡單的配置方式及強大的默認配置支持,使其可以輕鬆自由的存在於輕量與重量之間。事實上,Spring同樣支持使用JPA來操作數據對象(例如JpaTemplate),此外Spring提供了@PersistenceContext註釋來支持JPA。在輕量級 Spring 框架的第二代中添加了一大批特性,即使是新的服務器應用程序開發人員也能夠輕鬆上手。其關鍵增強之一就是 Spring 2 JPA的集成。@PersistenceContext註釋的使用示例如下面的代碼所示:

package quickstart.service;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.transaction.annotation.Transactional;

import quickstart.model.Person;

@Transactional
public class PersonServiceImpl implements PersonService {
     private EntityManager em;

     @PersistenceContext
     public void setEntityManager(EntityManager em) {
         this.em = em;
     }

     @SuppressWarnings("unchecked")
     public List<Person> findAll() {
         Query query = getEntityManager().createQuery("select p FROM Person p");
         return query.getResultList();
     }

     public void save(Person person) {
         if (person.getId() == null) {
             // new
             em.persist(person);
         } else {
             // update
             em.merge(person);
         }
     }

     public void remove(int id) {
         Person person = find(id);
         if (person != null) {
             em.remove(person);
         }
     }

     private EntityManager getEntityManager() {
         return em;
     }

     public Person find(int id) {
         return em.find(Person.class
id);
     }

}

@PersistenceContext會讓Spring在實例化的時候給服務注入一個EntityManager@PersistenceContext註解可以放在實例變量,或者setter方法前面。如果一個類被註解爲@TransactionalSpring將會確保類的方法在運行在一個事務中。

Spring JPA 應用程序在 Tomcat 上運行時,要讓 JPA 支持正常工作,需要在類裝入期間進行字節碼連接。來自 Tomcat 的標準類裝入器不支持這個,需要用特定於 Spring 的類裝入器實現這個功能。要把這個特定於 Spring 的類裝入器安裝到 Tomcat 服務器,首先要把 spring-tomcat-weaver.jar 拷貝到 Tomcat server/lib 子目錄。這個目錄包含的庫屬於 Tomcat 服務器私有,可以在 Spring 2 下載的 dist/weaver 目錄下找到 spring-tomcat-weaver.jar 庫。

四、        提供商無關性

開發者選擇JAVA平臺的一個最重要的原因就是它的提供廠商無關性。EJB 3.0是一個被設計爲對提供商沒有依賴性的開放的標準。EJB 3.0規範由企業JAVA社區的主流開源組織和廠商共同編寫和支持的。EJB 3.0框架使開發者的應用程序實現可以獨立於應用服務器。

比如,JBossEJB 3.0的實現是基於Hibernate的,OracleEJB 3.0實現是基於TopLink的,但是,在JBoss或者Oracle上跑應用程序,開發者既不需要去學習Hibernate,也不需要學習TopLink提供的獨特API。廠商無關性使EJB 3.0框架區別於當前其他任何的POJO中間件框架。

很多人認爲,儘管在任何應用服務器都上可以使用Spring框架,但基於Spring的應用仍然被限制於Spring本身,以及在應用中使用到的Spring提供的各種特別服務。但事實上是不是如此呢?大家應該知道,Spring的應用程序中,JtaTransactionManager使用了自動檢測機制,不管是MBeans應用服務器還是Tomcat應用服務器。同理,當使用JPA時,Spring自動檢測persistence.xml文件,並且創建EntityManagerFactory對象。在上面這些機制中,Spring不管是採用註釋(如PersistenceContext@Transactional@Resource等等)還是採用XML(如”jee:indi-lookup”等等),都可以像EJB應用一樣的與應用服務器提供商無關。

五、        小結

筆者認爲,EJBSpring設計的角度根本不同,就目前來看,還不能說哪一個能完全打倒另外一個。首先EJB最初的設計思想考慮的是爲分佈式的應用服務的。就因爲這個原因,使得開發一個EJB不難,但是開發一個好的EJB卻非常難。此外對於中小型的應用項目而言,基本不採用分佈式的解決方案,那麼爲什麼要採取一個爲分佈式設計的方案來解決非分佈式的問題呢? Spring就是爲了解決這個問題而誕生的。

本文中,筆者希望比較客戶的評價Spring相對EJB所具有的一些特性,同時,Spring可以與EJB進行協同的工作,Spring可以應用到EJB應用中去,同樣,EJB可以在Spring應用中很好的使用。同時,Spring如今有力的支持註釋:@Resource@PersistenceContext@PostConstruct@PreDestroy@EJB@WebServiceRef。當然,Spring 中不只是能使用Hibernate這樣的ORM框架,同樣可以使用JPA。更妙的是,Spring越來越與應用服務器提供商無關了,很容易實現在不同的應用服務中進行移植。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章