EJB2.1 EJB3.0 Spring

  
 
Java annotations are the key behind EJB 3.0, which ties POJO services, POJO persistence, and dependency injection altogether into a complete enterprise middleware solution.
 
EJB 3.0's annotation-driven programming model
Annotations have two key advantages:
they replace excessive XML-based configuration files
and eliminate the need for the rigid component models.
  1. What can we benefit from EJB3.0?
主要來說,EJB 3.0減少了在創建EJB時所需的類、接口、部署描述符的數量。EJB 3.0通過用POJO取代抽象bean類,用POJI取代組件與主接口(Component & Home),簡化了EJB的開發過程, 在此,後者是可選項--你不必全部包含進它們。
 
部署描述符--ejb-jar.xml--由其指定了EJB名、bean對象名、接口、查找者方法、容器管理關係(CMR),在此就不再需要其他與開發商相關的部署描述符了,因爲已被組件類中的元數據註釋所取代。這就是你爲什麼需要使用
JDK5.0來開發EJB .0應用的原因,因爲它們使用了註釋,而註釋在
JDK 5.0之前不可用。
EJB2.1時代,POJO必須通過接口來向框架聲明一些東西,這就造成了框架的侵入性,強迫POJO實現一堆接口。
2.Annotations vs XML?
The two differ in that XML files are processed separately from the code, often at runtime, while annotations are compiled with the code and checked by the compiler.
Annotation的優點
 一是不需要強力的Factory類來維護XML配置信息,不需要定位配置信息在xml文件中的位置,可以很敏捷的進行即時反射。
 
二是不需要割裂配置文件和POJO,維護人員不需要經常同時打開xml pojo文件,並定位xml信息的位置。
 
 
Annotation也有弱點
 
一是需要編譯,不能動態更新。

 
二是真正需要割裂POJO和配置信息,不希望配置信息弄髒POJO的時候。

 
三是Hibernate,Struts等的 annotation如果堆在可憐的POJO很混亂,如果都搶Transation這個Annontation就更慘了。
 
annoation的表達能力有限,不如XML的強。
XML 有 verbosity
XML 沒 annotation robust(misspell a method name )
然而XML 比 annotation 更 flexible (not hard coded)
EJB 3.0用javax.persistence.EntityManager API取代了EJB 2.1中的查找者方法,通常EJB 2.1的客戶端應用使用JNDI名來獲得一個對實體(entity)及會話(session)bean對象的引用,而EJB 3.0客戶端應用則是使用@Resource、@EJB和@Inject。
在EJB2.1中,可使用javax.ejb包裝類與接口來開發實體與會話,在此,一個會話bean實現了SessionBean接口,而一個實體bean實現了EntityBean接口;相比之下,EJB3.0的會話與實體bean類是POJO,並沒有實現SessionBean和EntityBean接口。
 
一個EJB2.1的會話bean類指定了一個或多個ejbCreate方法、回調方法、setSessionContext方法和業務(business)方法
與此類似,一個EJB2.1實體指定了ejbCreate()、ejbPostCreate()、回調、容量管理持久性(CMP)、CMR的getter/setter和業務方法
一個EJB 3.0會話bean類只指定了業務方法;
同樣地,一個EJB3.0實體bean只指定了業務方法、對不同bean屬性的getter/setter方法及對bean關係的getter/setter方法。
 
EJB2.1主接口擴展了javax.ejb.EJBHome接口、另有一個本地主接口擴展了javax.ejb.EJBLocalHome接口;EJB2.1的遠程接口擴展了javax.ejb.EJBObject接口,另有一個本地接口擴展了
javax.ejb.EJBLocalObject接口。
在EJB3.0中,並沒有指定組件與主接口它們已被POJI取代,如果一個會話bean類沒有指定一個業務接口,那麼EJB服務器將從會話bean類中爲它生成一個POJI業務接口。
 
Migrating Session Bean
示例中的EJB2.1會話bean類BookCatalogBean指定了一個ejbCreate方法、
一個稱爲getEdition()的業務方法和一個回調方法:
// BookCatalogBean.java
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;

public class BookCatalogBean implements SessionBean
{
 private SessionContext ctx;
 public String getEdition(String title)
 {
  if(title.equals("Java & XML"))
   return new String("第二個版本");
  if(title.equals("Java and XSLT"))
   return new String("第一個版本");
 }
 public void ejbCreate(){}
 public void ejbRemove() {}
 public void ejbActivate() {}
 public void ejbPassivate() {}
 public void setSessionContext(SessionContext ctx)
 {this.ctx=ctx;}
}
 
在EJB 3.0會話bean中,可使用元數據註釋來指定bean類型,即使用@Stateful和@Stateless來分別指定Stateful(有狀態)或Stateless(無狀態)。也可在一個會話bean中用一個業務接口來取代組件與主接口,因爲業務接口是一個POJI,所以可用@Local和@Remote來指定其爲本地或遠程類型,而一個會話bean可同時實現本地與遠程接口。

  如果在bean類不指定接口類型(本地或遠程),那EJB服務器在默認情況下會自動生成一個本地業務接口,在此也可使用@Local和@Remote註釋來指定接口類
 
下面的EJB 3.0會話bean是一個POJO,其由前面的BookCatalogBean.java EJB 2.1無狀態會話bean移植而來,注意它使用了@Stateless註釋,實現了一個本地業務接口,並在@Local註釋中指定了本地接口類名。
 
// BookCatalogBean.java EJB 3.0 Session Bean
@Stateless
@Local ({BookCatalogLocal.java})
public class BookCatalogBean implements
BookCatalogLocal
{
 public String getEdition(String title)
 {
  if(title.equals("Java & XML"))
   return new String("第二個版本");
  if(title.equals("Java and XSLT"))
   return new String("第一個版本");
 }
}
 
另外,也要注意,通過@Local註釋,上面的EJB 3.0bean類用一個本地業務接口(POJI)取代了EJB 2.1中的組件與主接口。
Migrating EJB Session bean Client
一個EJB2.1會話bean的客戶端通過使用JNDI名可取得一個會話bean對象,如下所示的客戶端使用了BookCatalogLocalHome的JNDI名取得一個本地主對象,接着調用了create()方法,隨後,客戶端用getEdition(String)業務方法輸出特定標題的版本值。
 
import javax.naming.InitialContext;
public class BookCatalogClient
{
 public static void main(String[] argv)
 {
  try{
   InitialContext ctx=new InitialContext();
   Object objref=ctx.lookup("BookCatalogLocalHome");
   BookCatalogLocalHome catalogLocalHome = (BookCatalogLocalHome)objref;
   BookCatalogLocal catalogLocal = (BookCatalogLocal) catalogLocalHome.
   create();
   String title="Java and XML";
   String edition = catalogLocal.getEdition(title);
   System.out.println("標題的版本:" + title + " " + edition);
  }
  catch(Exception e){}
 }
}
 
在EJB3.0中,可通過依賴性注入,來獲取一個對會話bean對象的引用,
這通常由@Resource、@EJB,@Inject註釋來實現。如下所示的EJB3.0會話bean客戶端使用了@EJB註釋注入到BookCatalogBean類中,仍可由getEdition(String)業務方法來獲取標題的版本值。
public class BookCatalogClient
{
 @EJB
 BookCatalogBean catalogBean;
 
@Resource
     TimerService tms;
 
@Resource
SessionContext ctx;
 
@Resource (name="DefaultDS")
DataSource myDb;
 
@Resource (name="ConnectionFactory")
QueueConnectionFactory factory;
 
@Resource (name="queue/A")
Queue queue;

 String title="Java and XML";
 String edition=catalogBean.getEdition(edition);
 System.out.println("標題版本:" + title + " " + edition);

}
Session Bean lifecycle management
In EJB 3.0, you can specify any bean method as a callback by annotating it with the following annotations.
Unlike EJB 2.1, where all callback methods must be implemented even if they are empty,
EJB 3.0 beans can have any number of callback methods with any method name.
 
@PostConstruct
@PreDestroy
@PrePassivate
@PostActivate
@Init
@Remove
Here is an example of those lifecycle method annotations in CalculatorBean:
 
@Stateful
public class CalculatorBean implements Calculator, Serializable {
    // ... ...
   
    @PostConstruct
    public void initialize () {
        // Initializes the history records and load
        // necessary data from database etc.
    } 
   
    @PreDestroy
    public void exit () {
        // Save history records into database if necessary.
    }  
   
    @Remove
    public void stopSession () {
        // Call to this method signals the container
        // to remove this bean instance and terminates
        // the session. The method body can be empty.
    }
   
    // ... ...
}
 
Migrating Entity Bean

  本節講述如何遷移EJB 2.1的實體bean到EJB 3.0。一個EJB 2.1實體bean實現了EntityBean接口,其由getter和setter CMP字段方法、getter和setter CMR字段方法、回調方法及ejbCreate/ejbPostCreate方法組成。示例實體bean(見例1)--BookCatalogBean.java,由CMP字段標題、作者、發行者和CMR字段版本組成。
 
例1:BookCatalogBean.java
 
import javax.ejb.EntityBean;
import javax.ejb.EntityContext;

public class BookCatalogBean implements EntityBean
{
 private EntityContext ctx;
 public abstract void setTitle();
 public abstract String getTitle();
 public abstract void setAuthor();
 public abstract String getAuthor();
 public abstract void setPublisher();
 public abstract String getPublisher();
 public abstract void setEditions(java.util.Collection editions);
 public abstract java.util.Collection getEditions();

 public String ejbCreate(String title)
 {
  setTitle(title);
  return null;
 }

 public void ejbRemove() {}
 public void ejbActivate() {}
 public void ejbPassivate() {}
 public void ejbLoad() {}
 public void ejbStore() {}

 public void setEntityContext(EntityContext ctx)
 {
  this.ctx=ctx;
 }

 public void unsetEntityContext()
 {
  ctx = null;
 }
}
 
而這個EJB 2.1實體bean的ejb-jar.xml部署描述符(見例2)文件,指定了EJB類、接口、CMP字段、EJB QL查詢和CMR關係。BookCatalogBean實體Bean定義了一個查找方法findByTitle()、一個CMR字段及版本。
例2:ejb-jar.xml部署描述符
<?xml version="1.0"?>
<!DOCTYPE ejb-jar PUBLIC
"-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN"
"http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar>
 <enterprise-beans>
  <entity>
   <ejb-name>BookCatalog</ejb-name>
   <local-home>BookCatalogLocalHome</local-home>
   <local>BookCatalogLocal</local>
   <ejb-class>BookCatalogBean</ejb-class>
   <persistence-type>Container</persistence-type>
   <prim-key-class>String</prim-key-class>
   <reentrant>False</reentrant>
   <cmp-version>2.x</cmp-version>
   <abstract-schema-name>BookCatalog</abstract-schema-name>
   <cmp-field>
    <field-name>title</field-name>
   </cmp-field>
   <cmp-field>
    <field-name>author</field-name>
   </cmp-field>
   <cmp-field>
    <field-name>publisher</field-name>
   </cmp-field>
   <query>
    <query-method>
     <method-name>findByTitle</method-name>
     <method-params>
      <method-param>java.lang.String</method-param>
     </method-params>
    </query-method>
    <ejb-ql>
     <![CDATA[SELECT DISTINCT OBJECT(obj) FROM BookCatalog obj WHERE obj.title = ?1 ]]>
    </ejb-ql>
   </query>
  </entity>
</enterprise-beans>
<relationships>
 <ejb-relation>
  <ejb-relation-name>BookCatalog-Editions</ejb-relation-name>
  <ejb-relationship-role>
   <ejb-relationship-role-name>
    BookCatalog-Has-Editions
   </ejb-relationship-role-name>
   <multiplicity>One</multiplicity>
   <relationship-role-source>
    <ejb-name>BookCatalog</ejb-name>
   </relationship-role-source>
   <cmr-field>
    <cmr-field-name>editions</cmr-field-name>
    <cmr-field-type>java.util.Collection</cmr-field-type>
   </cmr-field>
  </ejb-relationship-role>
  <ejb-relationship-role>
   <ejb-relationship-role-name>
    Editions-Belong-To-BookCatalog
   </ejb-relationship-role-name>
   <multiplicity>One</multiplicity>
   <cascade-delete />
   <relationship-role-source>
    <ejb-name>Edition</ejb-name>
   </relationship-role-source>
  </ejb-relationship-role>
 </ejb-relation>
</relationships>
</ejb-jar>
相比之下,對應於EJB2.1實體bean類的EJB3.0實體Bean類是一個POJO,並且非常簡單(請看例3)。此bean類的EJB 3.0版本使用了元數據註釋@Entity,而EJB 2.1部署描述符ejb-jar.xml文件中用元素符指定的查找方法,在EJB3.0Bean類中,則使用@NamedQueries和@NamedQuery註釋來指定;ejb-jar.xml文件中用元素符指定的CMR關係,在EJB 3.0 Bean類中,則用元數據註釋來指定;另外,主要的關鍵字段通過@Id註釋來指定。表1中列出了一些EJB 3.0的元數據註釋。
 
例3:BookCatalogBean.java
 
import javax.persistence.Entity;
import javax.persistence.NamedQuery;
import javax.persistence.Id;
import javax.persistence.Column;
import javax.persistence.OneToMany;

@Entity
@NamedQuery(name="findByTitle", queryString =
"SELECT DISTINCT OBJECT(obj) FROM BookCatalog obj WHERE obj.title = ?1")

public class BookCatalogBean
{
 public BookCatalogBean(){}
 public BookCatalogBean(String title)
 {
  this.title=title;
 }

 private String title;
 private String author;
 private String publisher;

 @Id
 @Column(name="title", primaryKey="true")

 public String getTitle(){return title;}
 public void setTitle(){this.title=title;}
 public void setAuthor(String author){this.author=author;}
 public String getAuthor(){return author;}
 public void setPublisher(String publisher)
 {
  this.publisher=publisher;
 }
 public String getPublisher(){return publisher;}
 private java.util.Collection<Edition>editions;

 
 public void setEditions(java.util.Collection editions)
 {
  this.editions=editions;
 }
 @OneToMany
 public java.util.Collection getEditions(){return editions;}
}
 
表1:EJB 3.0常用元數據註釋
 
註釋
說明
註釋元素
@Entity
註明一個實體bean類。
 
@Table
註明實體bean表。
如果未指定@Table,表名與EJB名相同。
name, schema
@Id
註明一個主要關鍵屬性或字段。
 
@Transient
註明一個非持久性屬性或字段。
 
@Column
爲一個持久性實體bean屬性註明一個映射欄。
Name、primaryKey、nullable、length。
默認欄名爲屬性或字段名。
@NamedQueries
註明一組命名查詢。
 
@NamedQuery
註明一個命名查詢或與查找方法相關的查詢。
name, queryString
@OneToMany
註明一個一對多聯繫。
Cascade
@OneToOne
註明一個一對一聯繫。
Cascade
@ManyToMany
註明一個多對多聯繫。
Cascade
@ManyToOne
註明一個多對一聯繫。
Cascade
 
EJB2.1bean類中的查找方法findByTitle(),在EJB3.0中則使用相應的@namedQuery註釋
EJB2.1實體bean中的CMR關係,在EJB3.0實體bean中則使用@OnetoMany註釋。註釋@Id註明了標識符屬性標題,註釋@Column指定了與標識符屬性標題對應的數據庫欄。如果一個持久性實體bean屬性未用@Column註明,那EJB服務器會假定欄名與實體bean屬性名相同。而瞬態實體bean屬性通常用@Transient來註明。
 
Migrating EJB Entity  Bean Client
你可在實體bean主接口或本地主接口中使用create()方法,來創建一個EJB2.1實體bean主對象或本地主對象。通常,一個EJB2.1實體bean的客戶端可通過JNDI查找來獲取一個實體bean的本地或遠程對象。下面有一段示例代碼,其創建了一個EJB2.1實體bean的本地主對象。
 
InitialContext ctx=new InitialContext();
Object objref=ctx.lookup("BookCatalogLocalHome");
BookCatalogLocalHome catalogLocalHome = (BookCatalogLocalHome)objref;
 
//在得到一個引用之後,EJB 2.1的客戶端通過create()方法創建了一個本地對象。
BookCatalogLocal catalogLocal = (BookCatalogLocal)
catalogLocalHome.create(title);
 
//可通過查找方法,從一個本地主對象中取得一個本地或遠程對象。
//例如,你可像如下所示通過findByPrimaryKey方法取得一個本地對象。
BookCatalogLocal catalogLocal = (BookCatalogLocal)
catalogLocalHome.findByPrimaryKey(title);
 
//在EJB 2.1中,可使用remove()方法移除一個實體bean的實例:
catalogLocal.remove();
 
EJB3.0通過javax.persistence.EntityManager類實現了持久性、查找和移除。表2列出了EntityManager類中用於取代EJB 2.1方法的一些常用方法。更新
表2:EntityManager類方法
EntityManager方法
描述
persist(Object entity)
使一個實體bean實例持久化。
createNamedQuery(String name)
創建一個Query對象的實例,以執行命名查詢。
find(Class entityClass, Object primaryKey)
查找一個實體bean實例。
createQuery(String ejbQl)
創建一個Query對象,以運行EJBQL查詢。
remove(Object entity)
移除實體bean的一個實例。
 
在EJB 3.0實體bean的客戶類中,可使用@Resource註釋來注入EntityManager對象
@Resource
private EntityManager em;
 
可調用EntityManager.persist()方法來使一個實體bean的實例持久化,例如:
BookCatalogBean catalogBean = new BookCatalogBean (title);
em.persist(catalogBean);
類似地,可調用EntityManager.find()方法來取得一個實體bean的實例。
BookCatalogBean catalogBean = (BookCatalogBean)
em.find("BookCatalogBean", title);
 
在此還可以定義一個相當於命名查詢findByTitle的EJB 3.0客戶類查找方法(與EJB 2.1中的查找方法可不一樣),用createNamedQuery(String)方法取得一個Query對象。
Query query=em.createNamedQuery("findByTitle");
 
通過setParameter(int paramPosition, String paramValue)或setParameter(String parameterName, String value)方法設置Query對象的參數,注意此處的參數位置是從0開始的。
query.setParameter(0, title);
 
使用Query.getResultList()方法取得BookCatalogBean對象的一個集合,如果確定查詢只返回一個單一的結果,還可以使用getSingleResult()方法代替。
java.util.Collection catalogBeanCollection = (BookCatalogBean)query.getResultList();
 
最後,用EntityManager.remove(Object entity)方法移除實體bean的實例。
BookCatalogBean catalogBean;
em.remove(catalogBean);
 
例4演示了一個完整的EJB 3.0實體bean的無狀態會話bean客戶類。
例4:BookCatalogClient類
import javax.ejb.Stateless;
import javax.ejb.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;

@Stateless
public class BookCatalogClient implements BookCatalogLocal
{
 @PersistenceContext
 private EntityManager em;

 public void create(String title)
 {
  BookCatalogBean catalogBean=new BookCatalogBean(title);
  em.persist(catalogBean);
 }
 public BookCatalogBean findByPrimaryKey(String title)
 {
  return (BookCatalogBean)em.find("BookCatalogBean", title);
 }

 public java.util.Collection findByTitle(String title)
 {
  Query query=em.createNamedQuery("findByTitle");
  query.setParameter(0, title);
  return (BookCatalogBean)query.getResultList();
 }

 public void remove(BookCatalogBean catalogBean)
 {
  em.remove(catalogBean);
 }
}
 
persistence.xml
 
<entity-manager>
 <name>cal</name>
 <jta-data-source>java:/DefaultDS</jta-data-source>
 <properties>
    <property name="hibernate.dialect" 
            value="org.hibernate.dialect.MySQLDialect" />
    <property name="hibernate.cache.provider_class"
            value="org.jboss.ejb3.entity.TreeCacheProviderHook"/>
    <property name="hibernate.treecache.mbean.object_name"
            value="jboss.cache:service=EJB3EntityTreeCache"/>
 </properties>
</entity-manager>
 
以上的示例演示瞭如何把一個會話bean和實體bean從EJB 2.1遷移到EJB 3.0,從EJB 2.0遷移的情況也與此類似。
 
Message-driven Beans
 
@MessageDriven(activateConfig =
{
 @ActivationConfigProperty(propertyName="destinationType",
    propertyValue="javax.jms.Queue"),
 @ActivationConfigProperty(propertyName="destination",
    propertyValue="queue/mdb")
})
public class CalculatorBean implements MessageListener {
 public void onMessage (Message msg) {
    try {
      TextMessage tmsg = (TextMessage) msg;
      Timestamp sent =
          new Timestamp(tmsg.getLongProperty("sent"));
      StringTokenizer st =
          new StringTokenizer(tmsg.getText(), ",");
      int start = Integer.parseInt(st.nextToken());
      int end = Integer.parseInt(st.nextToken());
      double growthrate = Double.parseDouble(st.nextToken());
      double saving = Double.parseDouble(st.nextToken());
      double result =
          calculate (start, end, growthrate, saving);
      RecordManager.addRecord (sent, result);
    } catch (Exception e) {
      e.printStackTrace ();
    }
 }
 // ... ...
}
 
Transaction
@Stateless
public class CalculatorBean implements Calculator {
 // ... ...
 @TransactionAttribute(TransactionAttributeType.REQUIRED)
 public void updateExchangeRate (double newrate) throws Exception {
    // Update the database in a loop.
    // ... ...
    // The operations in the loop must all be successful or
    // the database is not updated at all.
 }
}
 
Interceptor
@Stateful
public class CalculatorBean implements Calculator {
 // Bean methods that are to be intercepted by "log()"
 // ... ...
 
 @AroundInvoke
 public Object log (InvocationContext ctx)
                            throws Exception {
    String className = ctx.getBean().getClass().getName();
    String methodName = ctx.getMethod().getName();
    String target = className + "." + methodName + "()";
    long start = System.currentTimeMillis();
    System.out.println ("Invoking " + target);
    try {
      return ctx.proceed();
    } catch(Exception e) {
      throw e;
    } finally {
      System.out.println("Exiting " + target);
      cal.setTrace(cal.getTrace() + "" +
                   "Exiting " + target);
      long time = System.currentTimeMillis() - start;
      System.out.println("This method takes " +
                          time + "ms to execute");
    }
 }
}
 
Migrating Web Services from EJB2.1 to EJB3.0
 
問題:
 
EJB2.1中部署一個Web service最爲顯著的問題如下:
1)Web service需要從一個會話EJB採用它的行爲,而這個會話EJB本身是和一個遺產層次——例如在EJB3.0之前的版本——是緊密聯繫在一起的,同時也具有一系列的爲EJB環境所需要的伴隨接口。
2)你需要定義一個傳統的Java接口,這個傳統接口將會用於提供服務端點,服務端點就是類似於在一個會話EJB中已經包含的遠程接口。
3)還需要另外一個配置文件——部署描述符——進一步的來指明EJB的服務行爲。
解決
對這些Web services EJB的問題的減輕分爲兩種主要的形式:註釋和POJO。註釋是可以被放置在Java源代碼文件中的元數據,爲的是能夠提供進一步的配置屬性或者處理指令來執行Java環境。在另外一個方面,POJO被拆分成java類,這些java類沒有遺傳依賴關係。
 
下面代碼展示的是在EJB3.0 中一個Web service
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebService;
@Stateless
@WebService(serviceName="Weather", portName="WeatherPort")
public class WeatherBean  {
@WebMethod
    public double hiTemp(String city) {
        // Perform lookup to DB or some other data source
        return temp;
    }
    @WebMethod
    public double lowTemp(String city) {
        // Perform lookup to DB or some other data source
        return temp;
    }
    @WebMethod
    public double avgTemp(String city) {
        // Perform lookup to DB or some other data source
        return temp;
    }
// This method will not be exposed through the web service
    public double fahrenheitToCelsius(double fahrenheit) {
        // Perform conversion
        return celsius;
    }
// This method will not be exposed through the web service
    public double celsiusToFahrenheit(double celsius) {
        // Perform conversion
        return fahrenheit;
    }
}
 
最頂端的註釋——@Stateless 和 @WebService——表示的是這個類將會被用作一個具有Web services功能的會話bean,而在@WebService旁邊的屬性,表示的是特定的Web services數據,這些數據在EJB2.1中是被放置在一個部署描述符中的。剩下的@WebMethod註釋是用來指定哪些方法將會作爲Web service接口被提供出來,換句話說,Web service接口就是那些使用一個用來描述EJB Web service的 WSDL契約的操作。

下面列出了一些EJB QL的增強特性:

  1) 支持批量更新和刪除。

  2) 直接支持內連接和外連接。FETCH JOIN運行你指出關聯的實體,Order可以指定只查詢某個字段。

  3) 查詢語句可以返回一個以上的結果值。實際上,你可以返回一個依賴的類比如下面這樣:  

  SELECT new CustomerDetails(c.id, c.status, o.count)

  FROM Customer c JOIN c.orders o

  WHERE o.count > 100  

  4) 支持group by 和having。

  
5) 支持where子句的嵌套子查詢。

  在提交的EJB3.0草案中,EJB QL與標準SQL非常的接近。實際上規範中甚至直接支持本地的SQL
 
現已有一些應用服務器支持EJB 3.0規範,如JBoss應用服務器、Oracle應用服務。不幸的是,這些應用服務器對EJB 3.0的實現會有所不同----它們可能沒有實現全部的EJB 3.0特性,所以,在開始編寫程序之前,一定要仔細閱讀相關應用服務器提供的文檔說明。
 
Spring VS EJB3.0

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

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

  這兩個框架有着一個共同的核心設計理念:它們的目標是爲松耦合的POJO類提供中間件服務。框架通過在運行時截取執行環境,或將服務對象注射給POJO類的方式,將應用服務和POJO類“連接”起來。POJO類本身並不關注如何“連接”,而且也很少依賴於框架。這樣,開發者可以將注意力集中在業務邏輯上,可以對他們的POJO類進行與框架無關的單元測試。並且,由於POJO類不需要繼承框架的類或實現框架提供的接口,開發者可以在更加靈活性的基礎上構建繼承體系,和搭建應用。
 
   儘管有着共同的理念,但這兩個框架採取了不同的方式來提供POJO服務。
提供商無關性
EJB 3.0框架使開發者的應用程序實現可以獨立於應用服務器。比如,JBoss的EJB 3.0的實現是基於Hibernate的,Oracle的EJB 3.0實現是基於TopLink的,但是,在JBoss或者Oracle上跑應用程序,開發者既不需要去學習Hibernate,也不需要學習TopLink提供的獨特API。廠商無關性使EJB 3.0框架區別於當前其他任何的POJO中間件框架。(WebLogic 集成可嵌入的EJB3.0產品)
Spring一直是一個非標準的技術,使用的配置文件XML格式和開發接口都是私有的。如果你使用了Spring提供的特殊服務,如Spring事務管理器或者Spring MVC,你同樣被限制於Spring提供的APISpring一定程度上依賴於服務提供方(第三方)。
服務整合
EJB 3.0廠商可以輕鬆的優化整體性能和開發者體驗。如,在JBoss的EJB 3.0實現中,當你通過實體管理器持久化一個實體BEAN POJO時,Hibernate session事務將在JTA事務提交時自動提交。通過使用簡單的@PersistenceContext註解(例子參看後面文章),你可以甚至可以將實體管理器和其下的Hibernate事務綁定到一個有狀態的session bean上。應用程序事務可以在一個session中跨越多個線程,在事務性的WEB應用中這是非常有用的,如多頁面的購物車。
EJB 3.0中整合服務的另一個好例子是集羣支持。假如你部署一個EJB 3.0應用到一個集羣服務器,所有的故障切換、負載均衡、分佈式緩存、和狀態複製服務對於應用程序來說,都是自動完成的。集羣服務被隱藏在EJB 3.0編程接口之下,對於EJB 3.0開發者來說,這些服務都是完全透明的。

  在Spring中,優化框架和服務之間交互更加困難一些。例如,想要用Spring的聲明式事務服務來管理Hibernate事務,必須在XML配置文件中明確的配置Spring的事務管理器(TransactionManager)和Hibernate SessionFactory對象。Spring應用開發者必須自己管理跨越多個HTTP請求的事務。並且,沒有簡單的方法可以在Spring應用中實現集羣服務
 
 
 
服務聚合的靈活性
如果一個應用不是一個單一的結點,你將需要連接多個應用服務器提供的服務(如資源池、消息隊列和集羣)。這種情況下,從總的資源消耗上看,Spring框架就和任何EJB 3.0方案一樣是重量級的(有人說Spring 是輕量級的,EJB是重量級的。)。
EJB 3.0應用中,大多數的組件都是簡單POJO,他們可以容易進行容器外的單元測試。但是,如果要測試與容器服務相關的服務對象(如持久化實體管理器),更好的方式是進行容器內的測試,因爲這樣比使用假對象來替代的方式更加容易,更加健壯,而且更加準確。
 
EJB 3.0Spring相互學習了很多特性,所以,它們都在某種層次上支持XML和註釋。
EJB 3.0Spring都將運行時服務(如事務管理、安全、日誌、消息、和信息服務)連接給應用程序。這些服務被服務容器(如EJB 3.0Spring)以不可見的方式在運行時提供給應用程序。Spring AOP的方式。EJB用容器來管理。
 
EJB3.0引入的攔截器爲EJB組件注入了AOP活力,使得業務代碼同攔截器代碼完全分離。
用攔截器的場合,非常多,比如日誌、執行審計、安全性檢查等。
 
 
與Spring 在IoC,AOP 方面的比較
各種Bean的生命週期及回調方法
團隊的融合問題
完全的新技術
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章