J2EE业务层模式--业务代表
问题:
与业务服务组件远程通信的任务复杂度很高,需要对客户端隐藏这种复杂度。
当客户端直接访问远程业务服务组件时,可能发生以下的问题。
客户端直接与业务接口交互。这意味着,当这些业务服务接口代码改变时,客户端代码也可能需要改变。这就增加了系统维护的工作量,降低了系统的灵活性。
另一个问题与网络传输性能有关。当客户端直接与客户API直接交互时,客户端的一个操作,就可能需要与业务服务进行细粒度多次复杂的交互。这些导致吧业务逻辑完全的置入客户端,不采用任何客户端缓存,也不使用任何服务器端聚合,由此降低了系统的可维护性。而既然多次远程交互都要经过网络完成,这也降低了系统网络传输性能。
第三个问题是,让客户端如此紧密的和业务服务API交互,可能意味着,客户端代码为了一个远程分布的中间层交互,就必须包含一些底层架构代码。这些底层架构代码包括:命名服务比如JNDI,网络连接故障、以及重试逻辑等等。
注意:客户端,指的是表现层的客户端,可以有很多种客户端。
约束:
--需要使表现层组件和客户端<后者包括各种设备、web service、大型客户端程序等等>访问业务服务层。
--要尽可能的降低客户端与业务服务层之间的耦合,从而隐藏服务层的具体实现细节<比如寻址、访问等等>
--要避免不必要的远程服务调用
--要把网络异常信息转义成应用程序异常,或者是用户使用异常
--要吧服务创建、重配置、调用重试等细节对客户端隐藏起来。
解决方案:
使用业务代表模式,封装对业务服务的访问。业务代表模式隐藏了服务层的具体实现细节<比如寻址、访问机制等等> 。
业务代表能起到客户端业务抽象的作用:他抽象并隐藏了业务服务器的实现细节。因此,采用采用业务代表能够降低客户端和业务服务层之间的耦合。根据业务代表模式的具体实现策略的不同,他能有不同的程度的起到隔离作用,是客户端免受业务层改动的影响。所以,采用本模式具有一定的潜在效果,当业务服务层API或者他的顶层实现改动时,客户端的改动则可能大大的减少。
但是,如果业务层API发生改变时,业务代表的接口方法肯能仍然需要修改。不过显然,业务服务层内部发生改变的可能性,远比业务代表改动的可能性的大得多。
如果一个设计目标会导致一系列从头到尾的附加工作,而回报却要到未来才能够看得到(比如吧业务层抽象出来的设计),开发人员可能对此抱有怀疑,不过业务代表的确有一下的好处:
--主要好处是隐藏了底层服务的细节。比如说,采用业务代表后,命名、寻址之类的服务对客户端来说就完全的透明了,言下之意,就是说改动这些服务的实现细节不会影响到客户端代码。
--业务代表能够处理各种服务端的异常,比如java.rmi.Remote异常/JMS异常等等。业务代表可以吧这些系统级的异常转换成应用程序的异常。对于客户端来说,应用程序异常比较容易处理,而对实际用户来说,往往也比较友好。
--当服务层工作发生故障的时候,业务代表能够透明的做出重试或者恢复操作,无需让客户端知道这类异常--只有业务代表能够断定,这个问题没有法子自行解决,才会通知客户端。有了这样明显的收益,采用业务代表模式自然顺利成章。
--业务代表能够缓存结果数据,以及对远程业务服务的引用。采用缓存,能够明显显著改善系统性能。因为系统中可能存在一些对于的往返传输,他们会造成一定的潜在开销,缓存能够大大限制这些往返传输,从而提高传输性能。
业务代表会使用服务定位器来定位特定的业务服务。服务定位器负责隐藏寻址细节。
当业务代表和会话门面一起使用时,他们往往有一对一的关系。原因如下:封装一个业务代表中的逻辑,可能会与多个业务服务产生交互,因此,本来会在业务代表和和业务服务之间产生一对多的关系但是这样的多个业务服务又往往会被组装到同一个会话门面中。所以业务代表和会话门面就有一对一的关系。
我们把业务代表模式归结为业务层模式,而不是表现层模式,是以往内业务代表是中逻辑的抽象,而不是物理的抽象。在同表现层协作时,业务代表组件事实上居于表现层之中。但是这些组件又是业务层的一种扩展,处于以上原因,有因为这一模式会与会话门面的紧密联系,我们建议由负责业务服务层的开发人员来实现业务代表。