论坛首页 Java版 企业应用

说说EJB3的CallBack.

浏览 1802 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
最后更新时间:2005-12-22
最近开发了一个银行的信用证系统原型。主要目的是检验我们刚推出的EJB3 Alhpa版本,找出并修复
产品的一些Bug,以及加入了一些新的特性。在开发的过程中,我们总结了一些更好的使用EJb3进行
领域模型设计的经验,这些我想最终会一一以文章的形式写出来的,其中最值得引人注意的是CallBack
的使用。:)
CallBack在EJb3 spec中不过是一小章节,似乎不是很引人注意,刚开始,也没有引起我们的多少注意,
然而,在开发中,当我们实际运用它来解决问题的时候,发现它的实际作用还是很大的。
其实,从根本来说,CallBack相当于ORM Engine和用户设计的Domain Model(可持久话的模型)
之间一道天然的钩子,通过它,设计者可以放入很多类似横切面的关注点。
下面给出一个真实的例子:
需求:
银行需要对涉及帐务每一个操作实行录入,复核机制。假设操作涉及实体有Customer,Account。
录入纪录实体为InputRecord, 复核纪录为:ConfirmRecord.用户为User。
初步设计时,这些类的骨干代码为:
[code:1]@Entity
class User{
@Id
long id=-1;
String userName;
String passwordHex;
}
@Entity
class Customer{
@Id
long id=-1;
String name;
@OneToOne
InputRecord inputRecord;
@OneToOne
ConfirmRecord confirmRecord;
}
@Entity
class Account{
@Id
long id=-1;
String accountName;
String accountNo;
@OneToOne
InputRecord inputRecord;
@OneToOne
ConfirmRecord confirmRecord;
}
//Not a persistence Entity
abstract class OperationRecord{
@Id
long id=-1;
@ManyToOne
User user;
Date date;
}
@Entity
class InputRecord extends OperationRecord{
//nothing ,just define a concrete class and table
}
@Entity
class ConfirmRecord extends OperationRecord{
//nothing ,just define a concrete class and table
}
[/code:1]

上面这段代码有几点需要说明一下:

1) OperationRecord没有声明为Entity,这里没有用到继承策略,因为对象继承与
数据库之间的映射并不是很好,在一般设计中,我是很少使用它的,
继承和数据共享两者是没有什么关联的, 因为在内存中,他们的实例始终是互补
相干的数据副本,单纯从数据来说,分别对应到不同的表中来存储就是最好的映射,
而行为的继承在JVM中可以得到完全的体现。
基于这个认识,InputRecord,ConfirmRecord仅仅起表明类型的作用。
2)从Account,Customer的代码中可以看出InputRecord,ConfirmRecord域是重复出现的,
而且从需求来看,会有更多的实体需要这两个Field,从1)的分析中,很自然而然的抽取
一个基类出来:

[code:1]abstract class ConfirmableEntity{
@OneToOne
InputRecord inputRecord;
@OneToOne
ConfirmRecord confirmRecord;

}
        class Customer extends ConfirmableEntity{

        }



[/code:1]
到这里,一个对需求的思考同时也出现了,在什么地方纪录操作记录呢?
AOP? TemplateMethod? 很多种可选的方案。然而,从代码量和简洁性来说,CallBack是好的。
采用CallBack的基本骨干代码如下:
[code:1]abstract class ConfirmableEntity{
@PostPersist
public void registerInputRecord(){
//retrieve current user
User currentUser = UserHolder.getCurrentUser();
//create an inputRecord for current User
InputRecord inputRec = new InputRecord(currentUser);
setInputRecord(inputRec);
}
}
[/code:1]
所有的需要录入复核得实体只要继承自这个ConfirmableEntity,不仅获得数据,同样获得了相应的行为。
这么一段代码对于他们来说基本上时透明的。(有点类似AOP? )
上面的代码中,UserHolder是一个非常有意思的设计,用户的保持一般有不同的需求,在Web中有Session,
而在别的应用中就不一定使用这样的机制了,但不管如何,我们总归有在领域层提出获取当前操作用户的需求,
一个很简单的设计会让很多事情变得简单,可以把UserHolder当作一个隔离领域层和具体App层用户管理的
接口,大家如果对它得出现比较有诧异的话可以再具体讨论一下。:)

值得一说的是,这样的设计对于以后的可扩展也带来了巨大的影响,比如,用户提出需求:
对于已经复核得操作纪录不能再被修改,删除。
那么我们只要再在ConfirmableEntity上写一个CallBack即可:
[code:1]abstract class ConfirmableEntity{
@PostPersist
public void registerInputRecord(){
//retrieve current user
User currentUser = UserHolder.getCurrentUser();
//create an inputRecord for current User
InputRecord inputRec = new InputRecord(currentUser);
setInputRecord(inputRec);
}
@PreUpdate
@PreRemove
public void check(){
if(getConfirmRecord()!=null && getConfirmRecord().getId()>0 )
throw new SecurityException("can not update/remove confirmed record");
}
}[/code:1]
   
最后更新时间:2005-12-22
老大什么公司的呀会出产EJB的?
   
0 请登录后投票
最后更新时间:2005-12-23
引用
这么一段代码对于他们来说基本上时透明的。(有点类似AOP? )

要继承就说不上透明了.
AOP?
如果把持久化理解为一个方面,那么这里callback代表了固化的pointcut和advice.
aop是指面向方面编程,语言中包括方面这个概念.
   
0 请登录后投票
最后更新时间:2005-12-23
nihongye 写道
引用
这么一段代码对于他们来说基本上时透明的。(有点类似AOP? )

要继承就说不上透明了.
AOP?
如果把持久化理解为一个方面,那么这里callback代表了固化的pointcut和advice.
aop是指面向方面编程,语言中包括方面这个概念.

是的,也是因为考虑到这点,才没有唐而璜之的说是AOP,它需要继承。
这里的继承是顾及数据(InputRecord,ConfirmRecord)和行为(callBack)的,
他算不上AOP,但至少算得上方面的关注。 赫赫
   
0 请登录后投票
最后更新时间:2005-12-23
引用
老大什么公司的呀会出产EJB的?


我的失误。 :D  红工场,我们是红工场,网站www.redsoftfactory.com
   
0 请登录后投票
论坛首页 Java版 企业应用

跳转论坛:
JavaEye推荐