浏览 1802 次
|
锁定老贴子 主题:说说EJB3的CallBack.
精华帖 (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] 声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
最后更新时间:2005-12-22
老大什么公司的呀会出产EJB的?
|
|
| 返回顶楼 | |
|
最后更新时间:2005-12-23
引用 这么一段代码对于他们来说基本上时透明的。(有点类似AOP? )
要继承就说不上透明了. AOP? 如果把持久化理解为一个方面,那么这里callback代表了固化的pointcut和advice. aop是指面向方面编程,语言中包括方面这个概念. |
|
| 返回顶楼 | |
|
最后更新时间:2005-12-23
nihongye 写道 引用 这么一段代码对于他们来说基本上时透明的。(有点类似AOP? )
要继承就说不上透明了. AOP? 如果把持久化理解为一个方面,那么这里callback代表了固化的pointcut和advice. aop是指面向方面编程,语言中包括方面这个概念. 是的,也是因为考虑到这点,才没有唐而璜之的说是AOP,它需要继承。 这里的继承是顾及数据(InputRecord,ConfirmRecord)和行为(callBack)的, 他算不上AOP,但至少算得上方面的关注。 赫赫 |
|
| 返回顶楼 | |
|
最后更新时间:2005-12-23
|
|
| 返回顶楼 | |








