EJB设计模式
来源:互联网 发布:linux mount media 编辑:程序博客网 时间:2024/04/28 15:17
一:
第一个设计模式非常简单。一个公司和雇员的Entity Bean和
下面给出的Entity Bean的代码片断是类似的。它们是由jbuilder4的
EntityBean模版生成的。所有的字段都声明为public的cmp字段。
Code snippet for Company Entity Bean
public class CompanyBean implements EntityBean {
EntityContext entityContext;
public Integer comId; //the primary key
public String comName; //the company name
public String comDescription //basic description
public Timestamp mutationDate //explained later
public Integer ejbCreate(<params>) throws
CreateException {
return null;
}
//various get() and set() for every column/field
// which are exposed in the Remote Interface as well
Code snippet for Employee Entity Bean
public class EmployeeBean implements EntityBean {
EntityContext entityContext;
public Integer empId; //the primary key
public Integer comId; //the company foreign key
public String empFirstName; //the employee firstname
public String empLastName // the employee lastname
public Timestamp mutationDate //explained later
public Integer ejbCreate(<params>) throws
CreateException {
return null;
}
//various get() and set() for every column/field
// which are exposed in the Remote Interface as well
这个设计模式虽然很简单,但是却有很多缺点,比如,对每一个
字段的访问都会导致对get()和set()方法的一次远程调用。而远
程过程调用(RPCs)是非常耗费资源的,并且,对于在实际中通
常要求的组合的访问会导致一系列的远程调用。可以说,这个模
式在实际中可用性很差。上面展示的设计模式可以作为其他设计
模式的基础,比如RAD,原型设计,测试等。这时,那个代表雇
员的Employee Entity Bean并没有展示出在雇员和公司之间有何
关系。
二:
为了避免设计模式1的缺点,我们介绍一下封装
entity bean值域的value objec的概念。value object,
用某些语言的术语来说,就是一个结构类型,因为他们
和corba的结构类型非常类似。
value Object code snippet for Company
public class CompanyStruct implements
java.io.Serializable {
public Integer comId; //Primary Key
public String comName;
public String comDescription;
public java.sql.Timestamp mutationDate;
}
value Object code snippet for Employee
public class EmployeeStruct implements
java.io.Serializable {
public Integer empId; //Primary Key
public Integer comId; //Foreign Key
public String empFirstName;
public String empLastName;
public java.sql.Timestamp mutationDate;
}
现在,公司和雇员的entity bean可以把上面的一个结构类型作为
ejbCreate()的一个参数。由于这个结构封装了entity的所有字段
的值,entity bean只需要一个getdata()和setdata()方法就可以
对所有的字段进行操作。
Code snippet for an Entity Bean’s create()
public Integer ejbCreate(CompanyStruct struct) throws
CreateException {
this.comId = struct.comId;
this.comName = struct.comName;
this.comDescription = struct.comDescription;
this.mutationDate = struct.mutationDate;
return null;
}
Code snippet for an Entity Bean’s getData()
public CompanyStruct getData() {
CompanyStruct result = new CompanyStruct();
result.comId = this.comId;
result.comName = this.comName;
result.comDescription = this.comDescription;
result.mutationDate = this.mutationDate;
return result;
}
Code snippet for an Entity Bean’s setData()
public void setData(CompanyStruct struct) {
this.comName = struct.comName;
this.comDescription = struct.comDescription;
this.mutationDate = struct.mutationDate;;
}
跟设计模式1中使用单独的get()和set()方法去操作特定字段不同,
在设计模式2中,我们避免这种情况而只需要进行一次远程调用就
可以了。现在,只有一个事务通过一次远程调用就操作了所有的数
据。这样,我们就避免了设计模式1的大部分缺点,除了建立bean
之间的关系外。
虽然setdata()方法可以对所有字段赋值,但是,borland appserver
提供了一种智能更新的特性,只有被修改过的字段才会被重新写入数
据库,如果没有字段被修改,那么ejbStore()方法将会被跳过。
borland程序员开发指南(EJB)有更详细的描述。
同样,在entity bean和struct之间存在这重复的代码,比如同
样的字段声明。这意味着任何数据库表结构的修改都会导致
entity beabn和struct的改变,这使得同步entity和struct变得
困难起来。
就是在ebCreate()方法中调用setddata()方法,这可以消除一
些冗余的代码。
Code snippet for an Entity Bean’s create()
public Integer ejbCreate(CompanyStruct struct) throws
CreateException {
this.comId = struct.comId; //set the primary key
setData(struct);//this removes some redundant code
return null;
}
三:
在设计模式2中我们看到,在entity bean和struct之间
有很多重复的代码比如同样的字段声明(对应数据库中的表列)。
如果让entity bean从结构继承下来就可以避免冗余的代码。但是
这种设计,仍然不能显示beans之间的联系。
Code snippet for Company Entity Bean
public class CompanyBean extends CompanyStruct
implements EntityBean {
EntityContext entityContext;
//all fields in CompanyStruct are available for CMP
public Integer ejbCreate(CompanyStruct Struct)
throws CreateException {
this.comId = struct.comId; //set the primary key
setData(struct);//this removes some redundant code
return null;
}
其余的代码比如getdata()和setdata()方法的实现和设计模式2中
是完全一样的。
四:
在设计模式3中我们看到使bean从struct继承后使得代码大
幅缩水并且所有的字段都可定义为cmp字段。这里,我们可
以更进一步修正setdata()和getdata()的实现方法来减少代码量。
我们为这个struct增加一个方法。
value Object code snippet for Company
public class CompanyStruct implements
java.io.Serializable {
public Integer comId;
public String comName;
public String comDescription;
public Timestamp mutationDate;
public void copyFrom(CompanyStruct struct) {
comId = struct.comId;
comName = struct.comName;
comDescription = struct.comDescription;
mutationDate = struct.mutationDate;
}
}
由于entity bean是从struct继承下来的,在bean的实现类
中也一样可以引用copyfrom()方法,当然,必须注意的是,
这个copyfrom()方法并不是一个商业方法,它不需要在bean
的远程接口中暴露给调用者。
现在,getdata()和setdata()方法可以简化更进一步的简化。
Code snippet for an Entity Bean’s getData()
public CompanyStruct getData() {
CompanyStruct result = new CompanyStruct();
result.copyFrom(this);
return result;
}
这里把this作为一个参数传入copyfrom()。由于enttity bean
从struct继承而来,于是这个entitty bean便可以作为一个
struct传入。
EJB容器并不赞成把this指针作为一个参数传递因为在两个控
制线程中同时访问一个bean的实例可能会引起事务冲突。但事
实上我们所做的并没有违背这个原则,因为我们的并没有在
bean之间传递this的引用并且也没有引用任何可能引起事务冲突的方法。
Code snippet for an Entity Bean’s setData()
public void setData(CompanyStruct struct) {
this.copyFrom(struct);
}
对于一个映射到有很多列的表的entity bean,这种实现
方法的优点是使得bean实现类的代码非常简单。这种设
计模式使得代码及其精简,可读性和可维护性也大大增强。
任何数据库的修改都只需要修改作为基类的struct,而几
乎不需要修改bean的代码。把这种改变从struct分离出来,
当cmp字段发生改变时需要修改部署描述符。这就使得开
发时能够更好的适应设计的改变。
这里,还是没有实现bean之间的关系,这将在设计模式5中解决。
五:
就像我们在设计模式4中看到的, Entity Bean的实现大小被缩减到在ejbCreate(), getData()and setData()方法中的仅仅几行,不管CMP字段的数目.下一步是建模公司和雇员的Entity Beans,这个有点繁琐而且建议读者先对borland公司的<EJB程序员指南>的OR Mapping和高级CMP有所了解.
对这个关系建模根本不需要对结构的代码变化,然而Entity Beans实现类需要一点点修改来反映两个实体间的关系,鉴于此Deployment Descriptor需要有小的修改.
象以前, Entity Bean从结构继承,下面是公司Entity Bean的代码片段:
public class CompanyBean extends CompanyStruct
implements EntityBean {
EntityContext entityContext;
// CMP for all fields in the CompanyStruct
public java.util.Collection employees; //one-to-many
//rest of the code including getData() and setData()
public java.util.Collection getEmployees() {
return employees;
}
}
下面是雇员Entity Bean的程序片段:
public class EmployeeBean extends EmployeeStruct
implements EntityBean {
EntityContext entityContext;
//CMP for all fields in EmployeeStruct EXCEPT
//the comId
public Company company;//remote reference to company
}
在上面的程序片段中,雇员Entity Bean从雇员结构继承,雇员结构本身有
一个字段comId表示雇员和公司之间的的外键,在所有的前面的设计模式中,
这个字段是CMP的.而在设计模式5中这个字段用在Deployment Descriptor中un-checking的方法从CMP中去掉.而对公司Entity Bean的远程引用现在是CMP的.现在的问题是怎么在getData()和SetData()方法中更新公司Entity Bean的引用,当这些方法只get和set comId(在设计模式上下文中没有被CMP)的值.简单的说,过程的结构没有变化并且字段comId(不再CMP)在RPC中被拷贝到Entity Bean和从Entity Bean拷贝出来.需要的是对公司Entity Bean的远程引用在必须被写入数据库和从数据库读出时更新.我们需要用ejbLoad()和ejbStore()方法在Entity Bean实现类中为我们完成这项工作.
在雇员Entity Bean中的ejbLoad()方法的代码片段如下:
public void ejbLoad() {
try {
comId=(company ==
null)?null:(Integer)company.getPrimaryKey();
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
以上代码几乎不需要解释.当数据被从数据库中读出(在事务的开始时候),
comId(不是CMP)字段在雇员Entity Bean被set.因此当getData()方法被调用时,返回的结构将包含正确地comId的值.
在雇员Entity Bean中的ejbStore()方法如下:
public void ejbStore() {
try {
company = (comId ==
null)?null:beanGlossary.getCompanyHome().findByPrimary
Key(comId);
} catch (Exception e) {
//throw some runtime exception (e.g. EJBException)
}
}
ejbStore()在事务结束当数据被写入数据库时被调用.在这种情况下,comId的值被修改(通过调用setData方法),this必须被写到数据库中.在上面方法中的代码把comId转化成公司的远程引用.(毕竟comId是公司Entity Bean的主键).
使用空check的原因是数据库不能存空值(表之间的弱引用),并且这些同样需要建模.
任何情况下,用java对基本类型的封装要比使用基本类型自己好,因为他们能
存空值而且易于转换成其他形式.
上面的BeanGlossary类的代码片断容易引起一些混淆.
这实际上是一个捕获EJB的lookup的utility类(一个无状态session bean),
在entity bean和有状态session bean的情况下,Home接口的lookup是被缓冲的.在无状态session bean的情况下,Remote接口是被缓冲的(作为ejb规范1.1的一部分,一个SLSB在Home接口中调用的create()是不被优化的).
通过在上面上下文的缓冲,我们意思是第一个请求是被lookup的.随后的调用是得到已经在对象引用中初始化的home接口或remote接口.
BeanGlossarySB utility类的代码片段如下:
public class BeanGlossarySB implements SessionBean {
private Context context = null;
public javax.naming.Context getContext() throws
NamingException {
if (context == null)
context = new javax.naming.InitialContext();
return context;
}
// Company
private CompanyHome companyHome = null;
public CompanyHome getCompanyHome() throws
NamingException {
companyHome = ((CompanyHome)
javax.rmi.PortableRemoteObject.narrow(
getContext().lookup("java:comp/env/ejb/Company"),
CompanyHome.class));
return companyHome;
}
// rest of the EJBs
}
在设计模式5中,我们没有处理Entity Bean的Home接口.
在雇员Entity Bean的情况下, 会有一个finder元素在
findEmployeesByCompany(Company pCompany)的几行中,
这将会返回雇员远程引用的集合. 在公司Entity Bean 中的Deployment
Descriptor map了在上面定义的finder元素的雇员集合.
这样,在公司Entity Bean中的方法getEmployees()在remote接口中的调用
返回需要的与那家公司相联系的远程引用的雇员的集合.
- EJB设计模式1
- EJB设计模式
- EJB设计模式概述
- EJB中的设计模式
- EJB设计模式4
- EJB设计模式5
- EJB设计模式1
- EJB设计模式2
- EJB设计模式3
- EJB设计模式4
- EJB设计模式5
- EJB设计模式1
- EJB设计模式4
- EJB设计模式3
- EJB设计模式2
- EJB设计模式4
- EJB 设计模式概述
- EJB设计模式5
- 两个网页之间数据通信
- 女司机被强奸以后......
- 经理人必看的10个管理网站
- JNDI设计内幕
- Java RMI-IIOP 入门
- EJB设计模式
- 在留言的页面我想用一个下拉表来选择头像,并在选择时,头像在下拉表的右方显示
- ASP.Net生成静态HTML页
- VB.Net中动态创建Access数据库
- hibernate优化
- [C1.2] Fahrenheit-Celsius Table
- 载入时动态链接及运行时动态链接,译自MSDN
- 人生的秘诀
- 警示小故事(转)