message facade
一个ejb客户端想要在一个环境的用例中调用多个ejb的
方法,并且不需要从服务器的立即的反映。
怎样才能让ejb客户端在一个事务中调用多个session
bean或entity bean的方法,不需要被阻塞并且等待
每个bean的反映?
特别在大型系统中,伸缩性指明一个用例的商业逻辑
与客户端的分离执行,不需要客户端等待执行完毕。
这种类型的行为,叫做异步行为,允许客户端用最大的
反应时间和用户界面(UI)交互,因为他们不需要坐下来
等待他们启动的用例执行。这种方法允许大型系统伸缩,
因为用例能在一个批处理中排队并被执行,对用户透明,
用户可以马上转移到UI的下一个部分。如果排队的用例
的大部分已经开始发展,系统执行用例的部分也能被伸
缩并且通过系统升级,都不需要改变对客户端的可用性
和质量。
考虑一个简单的基于web的航线注册系统,在这个系统中
一个servlet接受为一个用户的特定的一个航班预定一个
座位的请求。在这种场景中,一个servlet必须用一个
航线注册一个用户,决定如果座位在一次航班上是否可用,
为一个用户预定一个座位,如图1.5所示。
在这个例子中,我们有一个客户端为了执行一个用例完成
对服务器的多个异步调用。这个过程的每一步需要一个
分离的网络调用并阻塞客户端的部分。在一个像航线
预定应用一样巨大的系统中,这个瓶颈显然是无法接受的。
还有,在这样的风格下执行逻辑减少了系统的可维护性和
可重用性,并且不为用例提供事务的一致性和分离性。
最通常的解决方案是使用session facade模式。用这个模式
,一个应用程序创建一个包含充满商业用例的商业逻辑的
session bean层。每个session bean在一个大块(bulk)调用中
代表客户端完成对entity bean或其他服务器端资源的大
块(bulk)操作,如session facade模式的图1.3所示。不幸的是,
即使整个用例是被session facade方法封装,这个方法仍然
有以下几个缺点:
1.无法接受的反应时间。一个和web站点交互的用户将不能
等待数秒以上。这个用例的执行需要能扩展不同的航线系统的
多个数据库的很多背景进程。因为对ejb层的调用是一个同步
调用,客户端将被阻塞直到整个过程结束。
2.不可靠/无容错机制。这个用例能潜在的涉及分布在3个
分离的ejb服务器的ejb和3个分离的数据库(一个为用户,
一个为航线,一个为航班)。如果任何这些服务器中的一个
当机了,整个过程将会失败,并且用户的预定请求将会丢失。
即使如果servlet层和只有一个ejb服务器通信,如果服务器
当掉了,过程也将失败。
使用session facade解决耦合,性能,可维护性,可重用性,
和一致性的问题,但不能完全解决反应和可靠性的问题。
当一个复杂和耗费时间的预定用例运行,客户端仍将只得
被阻塞。如果ejb服务器或任何它依赖的系统在用例执行时
没有运行,那么用例也会失败。
我们的讨论的结论是我们需要一个有容错机制的服务器端
抽象,它作为一个中介,在一个调用和一个事物中执行
用例(保护客户端不受服务器端对象模型的复杂性的影响),
不需要客户端被阻塞并等待用例完毕。Message-driven
beans是专门为这个设计的。
综上所述:
使用message-driven bean去创建一个容错的,异步的
facade。客户端应该只存取message-driven bean,不
存取entity bean。
使用message-driven bean(mdb)作为facade,通过增加
异步,容错方式执行用例的能力,增强了session facade
模式。当我们使用message facade,一个应用程序的每个
用例中的商业逻辑映射到它自己的mdb。
考虑先前的例子。我们的在一次航班上预定一个座位的
商业逻辑现在将在ReserveSeat mdb的OnMessage()方法
中被替换。这个mdb的目的是去封装所有和在一次航班
上预定一个座位有关的商业和工作流逻辑,并且去异步
执行,如图1.6所示。
这里我们有一个servlet客户端创建一个Java Message
Service(jms)消息并且传进需要的参数。这个servlet
构造一个容纳所有需要的参数(用户的primary key,
航班号,航线primary key)的消息并且发送这个消息
到一个被创建做预定座位用例的JMS 目标。通过在合适
的目标接受消息,客户端可以自由的继续(显示下一个
web页)。在这一点上,mdb容器将试图传送消息到下一个
可用的ReserveSeat mdb。如果所有的在池中的Reserve-
Seat mdb在消息接受时正在被使用,JMS服务器应该等待
直到下一个变成可用的。用session facade执行这个用例,
一个完全使用的session bean池将只有一个失败的点,
并且客户端将只有手工重试。
当一个mdb变成可用的,容器将执行OnMessage()方法。
在这一点上,ReserveSeat mdb将线性的通过执行用例的
过程:注册用户到航线,检查是否座位可用,并且定一个
座位。当消耗大量时间的过程发生,最终用户可以自由的
在站点上冲浪并且去做他(或她)自己的事。
message facade比session facade的一个重要优势是
异步执行用例能得到保证。那就是,如果事务在任何
点失败了(可能航线系统当掉了或其它系统失败发生
了),事物将会回滚并且JMS消息将会被放回到队列中。
事务将会晚些时候重试,无需客户端的知识。
这个幕后行为同样也展现了一个问题。如果用例失败了
或成功了,客户端怎样知道呢?举个例子,如果一个
座位不能被预定因为飞机被全部预定满了,客户端需要
知道。在一个同步模型中(使用session facade),客户
端将会立即知道。在一个异步模型中,客户端不再等待
得知用例是否成功,并且需要被用特定应用的FORM来提
醒。最通常的解决方案是email。如果用例成功或失败了
那么系统将用email通知用户。有些公司可能实现一个
系统用如下的方式:用人来打个电话,等等。如果应用
需求允许,有些应用能采用"拉"的模型。那就是,最终
用户将被分配一个特定的他们能去检查他们的请求的
状态的位置,和被现代导游服务采用的轨迹号(tracking
number)相似。
这里的结论是当使用message facade模式,开发者必须
设计新的方式去传递用例的结果到客户端。
使用message facade模式的一个缺点是现在商业逻辑
是同时分布到mdb(为message facade)和session bean
(为session facade)。这可能是大家最关心的,不过
在一个应用中保持商业逻辑到一个位置会更好一些。
一个解决这个问题的聪明的做法是在session facade
中实现所有的用例,并且用message facade代理session
facade。这种方法,所有使用一个异步的,容错的结构
如mdb的好处都被保留了,并同时保持逻辑只局限于在
session bean层。
message facade模式的优势包括所有的在session facade
模式中所列出的优点,并加上如下优点:
1.立即反映时间/异步通信。当一个客户端传送一个JMS
消息,它将自由的继续处理无需等待服务器完成用例并
反映。一个较长,复杂的用例因此能被启动而控制流立即
返回到用户。
2.消除失败的单独的点。使用messaging将保证你的应用
继续工作即使EJB服务器或其他它所依赖的子系统当掉了。
举个例子,如果数据库当掉了,mdb事务将不会完成,
ReserveSeat消息将保留在队列中并被晚些时候重试。如果
EJB容器当掉了,消息也将被储存。如果我们使用同步模型
这样的容错能力将不可能。当然,如果你的JMS服务器没有被
集群并且当掉了,同样代表一个单独的失败的点,不过至少
潜在危险的数目减少了。
然而,作为一个使用mdb的副产品,message facade也有如下
的缺点:
1.mdb有弱类型(动态)的输入参数。mdb的角色是消耗JMS消息,
这些消息在编译时看上去一样。这和session/entity bean
不一样,它们提高了java的内建强类型方法和remote和local
interface的参数去在编译时捕获通常的错误。开发者需要额
外的注意来用目的mdb所需的合适的内容来load一个JMS消息。
一个对这个问题的解决方案是去封装所有来自JMS的数据到
一个自定义的数据传输对象,并序列化这个对象到一个JMS
消息。
2.mdb没有任何返回值。既然mdb调用是异步的,message
facade不能用作需要在执行完后返回值的用例。使用
message facade因此表面上和使用session facade相似,
在session facade中所有的session bean方法简单的只返回
void。然而,使用JMS作为传输机制去从mdb回到消息创建者
得到一个反应是可能的,请参照书"Mastering Enterprise
java beans,second edition",看看关于这种机制的讨论。
3.mdb不传播异常到客户端。不像session/entity bean,
mdb不能从任何它们的方法中抛出应用异常或RemoteException
。mdb必须因此处理所有在一些特定应用格式中展现的异常。
(就是说,如果出现问题就给用户发邮件,记录错误到一个
管理日志中,等等)。
message facade是一个非常强大的建立去耦,高伸缩性的
应用的模式。一个典型的EJB系统将可能使用session facade
和message facade的结合。session facade是一个清楚的
为"读"类型操作的选择,这里客户端需要从服务器的一些数据
,或当客户端需要显式的等待用例完成。message facade是一
个清楚的更新操作的选择,在这里客户端无需立即看到更新
的结果。
message facade对session facade的伸缩性和容错性的优势
很明显。论及性能,一个基于消息的系统将比集群的session
bean方法更有伸缩性,因为mdb"拉";操作而不是把操作"推"到
它们。"拉";方法当我们把它们集群时伸缩得更好,因为用了
对系统资源的优化。
开发者应该在他们的设计中仔细评估每个用例,问他们自己
那个用例是一个同步的还是异步的。这将是选择一个模式还
是另一个模式的决定性因素。
相关模式:
session facade