分享
 
 
 

前进:从EJB 2.1到EJB 3.0

王朝other·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

在开始讨论怎样从EJB 2.1迁移到EJB 3.0之前,有必要先了解一下迁移之后将会得到什么:主要来说,EJB 3.0减少了在创建EJB时所需的类、接口、部署描述符的数量。EJB 3.0通过用纯旧式Java对象(POJO)取代抽象bean类,用纯旧式Java接口(POJI)取代组件与主接口(Component & Home),简化了EJB的开发过程,在此,后者是可选项--你不必全部包含进它们。

部署描述符--ejb-jar.xml--由其指定了EJB名、bean对象名、接口、查找者方法、容器管理关系(CMR),在此就不再需要其他与开发商相关的部署描述符了,因为已被组件类中的元数据注释所取代。这就是你为什么需要使用JDK 5.0来开发EJB 3.0应用的原因,因为它们使用了注释,而注释在JDK 5.0之前不可用。

EJB 3.0用javax.persistence.EntityManager API取代了EJB 2.1中的查找者方法,通常EJB 2.1的客户端应用使用JNDI名来获得一个对实体(entity)及会话(session)bean对象的引用,而EJB 3.0客户端应用则是使用@Resource、@Inject和@EJB。

在EJB 2.1中,可使用javax.ejb包装类与接口来开发实体与会话,在此,一个会话bean实现了SessionBean接口,而一个实体bean实现了EntityBean接口;相比之下,EJB 3.0的会话与实体bean类是POJO,并没有实现SessionBean和EntityBean接口。

一个EJB 2.1的会话bean类指定了一个或多个ejbCreate方法、回调方法、setSessionContext方法和业务(business)方法;与此类似,一个EJB 2.1实体指定了ejbCreate()、ejbPostCreate()、回调、容量管理持久性(CMP)、CMR的getter/setter和业务方法。一个EJB 3.0会话bean类只指定了业务方法;同样地,一个EJB 3.0实体bean只指定了业务方法、对不同bean属性的getter/setter方法及对bean关系的getter/setter方法。

EJB 2.1主接口扩展了javax.ejb.EJBHome接口、另有一个本地主接口扩展了javax.ejb.EJBLocalHome接口;EJB 2.1的远程接口扩展了javax.ejb.EJBObject接口,另有一个本地接口扩展了javax.ejb.EJBLocalObject接口。在EJB 3.0中,并没有指定组件与主接口--它们已被POJI取代,如果一个会话bean类没有指定一个业务接口,那么EJB服务器将从会话bean类中为它生成一个POJI业务接口。

请在脑海中记住这些变化,本文的后续部分,将用两个示例来集中讲述把一个会话bean和一个实体bean,从EJB 2.1迁移到EJB 3.0时所需的详细信息。

迁移会话bean

示例中的EJB 2.1会话bean类--BookCatalogBean--指定了一个ejbCreate方法、一个称为getTitle()的业务方法和一个回调方法:

// 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中的组件与主接口。

迁移EJB会话bean客户端

一个EJB 2.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){}

}

}

在EJB 3.0中,可通过依赖性注入,来获取一个对会话bean对象的引用,这通常由@Inject、@Resource、@EJB注释来实现。如下所示的EJB 3.0会话bean客户端使用了@Inject注释注入到BookCatalogBean类中,仍可由getEdition(String)业务方法来获取标题的版本值。

public class BookCatalogClient

{

@Inject BookCatalogBean;

BookCatalogBean catalogBean;

String title="Java and XML";

String edition=catalogBean.getEdition(edition);

System.out.println("标题版本:" + title + " " + edition);

}

迁移实体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>

相比之下,对应于EJB 2.1实体bean类的EJB 3.0实体Bean类是一个纯旧式Java对象(POJO),并且非常简单(请看例3)。此bean类的EJB 3.0版本使用了元数据注释@Entity,而EJB 2.1部署描述符ejb-jar.xml文件中用元素符指定的查找方法,在EJB 3.0 Bean类中,则使用@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;

@OneToMany

public void setEditions(java.util.Collection editions)

{

this.editions=editions;

}

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

EJB 2.1 bean类中的查找方法findByTitle(),在EJB 3.0中则使用相应的@namedQuery注释;EJB 2.1实体bean中的CMR关系,在EJB 3.0实体bean中则使用@OnetoMany注释。注释@Id注明了标识符属性标题,注释@Column指定了与标识符属性标题对应的数据库栏。如果一个持久性实体bean属性未用@Column注明,那EJB服务器会假定栏名与实体bean属性名相同。而瞬态实体bean属性通常用@Transient来注明。

迁移EJB实体Bean客户端

你可在实体bean主接口或本地主接口中使用create()方法,来创建一个EJB 2.1实体bean主对象或本地主对象。通常,一个EJB 2.1实体bean的客户端可通过JNDI查找来获取一个实体bean的本地或远程对象。下面有一段示例代码,其创建了一个EJB 2.1实体bean的本地主对象。

InitialContext ctx=new InitialContext();

Object objref=ctx.lookup("BookCatalogLocalHome");

BookCatalogLocalHome catalogLocalHome = (BookCatalogLocalHome)objref;

在上面的代码段中,BookCatalogLocalHome是BookCatalogBean实体bean的JNDI名。

在得到一个引用之后,EJB 2.1的客户端通过create()方法创建了一个本地对象。

BookCatalogLocal catalogLocal = (BookCatalogLocal)

catalogLocalHome.create(title);

在EJB 2.1中,可通过查找方法,从一个本地主对象中取得一个本地或远程对象。例如,你可像如下所示通过findByPrimaryKey方法取得一个本地对象。

BookCatalogLocal catalogLocal = (BookCatalogLocal)

catalogLocalHome.findByPrimaryKey(title);

另外在EJB 2.1中,可使用remove()方法移除一个实体bean的实例:

catalogLocal.remove();

EJB 3.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

@Local

public class BookCatalogClient implements BookCatalogLocal

{

@Resource

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);

}

}

以上的示例演示了如何把一个会话bean和实体bean从EJB 2.1迁移到EJB 3.0,从EJB 2.0迁移的情况也与此类似。

在本文完稿时,已有一些应用服务器支持EJB 3.0规范,如JBoss应用服务器、Oracle应用服务器及Caucho应用服务器。不幸的是,这些应用服务器对EJB 3.0的实现会有所不同----它们可能没有实现全部的EJB 3.0特性,所以,在开始编写程序之前,一定要仔细阅读相关应用服务器提供的文档说明。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有