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 提供的 API Spring 一定程度上依赖于服务提供方 (第三方)。
服务整合
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.0 Spring 相互学习了很多特性,所以,它们都在某种层次上支持 XML 和注释。
EJB 3.0 Spring 都将运行时服务(如事务管理、安全、日志、消息、和信息服务)连接给应用程序。这些服务被服务容器(如 EJB 3.0 Spring )以不可见的方式在运行时提供给应用程序。 Spring AOP 的方式。 EJB 用容器来管理。
 
EJB3.0 引入的拦截器为 EJB 组件注入了 AOP 活力,使得业务代码同拦截器代码完全分离。
用拦截器的场合 , 非常多,比如日志、执行审计、安全性检查等。
 
 
与Spring 在IoC,AOP 方面的比较
各种Bean 的生命周期及回调方法
团队的融合问题
完全的新技术
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值