大胃兄,哈,我还没仔细看呢。。而且对于EJB经验不多,不好意思讲啊:)

解决方案 »

  1.   

    第一章
    EJB层架构模式
    ================================================================================当我们开发人员第一次设计企业级JavaBean(EJB)系统时,面临的最困难的任务是选择正确的架构或者说逻辑分块以满足项目需求,这些需求包括:性能、可维护性和可移植性。这一章会讲到一些在当今实际应用的基本架构模式,具体的讲有如下几种:[会话面板模式] 作为最广泛使用的EJB设计模式,该模式表明如何正确的在你的系统中分割商务逻辑,以最大限度减轻客户端与服务器端的相互依赖,同时强制用例(use case)在单次网络调用和单个事务中执行。[消息面板模式] 消息面板模式处理的是何时以及怎样为那些本质上异步的用例划分逻辑。[EJB命令模式] 与会话面板模式相反,该模式提倡将商务逻辑放在轻量的、普通的Java命令bean中。使用该模式最大的好处是完全的将客户端与EJB本身分隔开来,并且在同一个网络调用和事务中执行用例。[数据传输对象工厂模式] 该模式反映出早先的将DTO创建/销毁逻辑放在实体bean中这种方式的弊端,建议将数据传输对象的创建/销毁逻辑集中到单个层中(通过会话bean或者普通的java工厂实现)。[通用属性访问模式] 该模式讨论何时以及怎样提供域内通用的接口来访问实体bean的属性以达到可维护性和性能的需求。[商务接口模式] 该模式展示了怎样实现一个能够提供编译期对远程/本地接口和EJB类的方法签名检查的接口实现机制。
    --------------------------------------------------------------------------------
    会话面板模式
    --------------------------------------------------------------------------------EJB的客户端需要执行商务逻辑以完成一个用例。[一个EJB的客户端如何才能在单个事务和一次较大的网络调用中执行某个用例的商务逻辑呢?] * * *为了执行某个典型的用例的商务逻辑,通常会需要访问甚至修改服务器端的多个对象(如会话bean和实体bean)。问题是多次细化的会话/实体bean的调用会产生多次网络调用(以及可能的多个事务)的开销,同时造成代码难以维护,因为数据访问和工作流/商务逻辑被分散在不同的客户端。考虑一个在线银行场景,一个servlet收到请求,要它为Web客户端从一个账户往另一个账户划账。在这种情况下(如图1.1所示),这个servlet必须:检查确认用户是被授权的、从一个银行账户的实体bean中提取资金、将资金存到另一个银行账户实体bean中。<图略>当通过实体bean的本地和远程接口调用方法时,这个方案在严重的负载情况下并不适用,因为整个过程需要至少6次网络调用:3次用于找到正确的实体bean,另外3次用于实际上的划账。还有,因为实体bean是事务性的,每一次对它的调用都需要服务器端一个单独的事务,要求将远程对象与其后台的数据存储同步化,还需要应用服务器相应的维护工作。更糟的是这个方案并不保证客户存款的安全。如果存入过程失败,客户的存款已经提出,这样他的钱就丢失了。用户验证、提款、存款都是单独进行的,如果存款失败,取款的过程就不会被回滚,造成状态不连贯。这里的问题在于,当直接调用实体bean的方法时,每次方法调用都是单独的工作,属于单独的事务。一个解决方案是往实体bean中加入额外的逻辑来处理单个客户调用并执行多项操作。这个方案会引入维护问题,因为我们的实体bean层很可能会随着时间推移需要对其进行各种各样的操作。如果我们每次当需要提升性能的时候就往实体bean里面增加逻辑的话,很快我们的实体bean就会变得臃肿并且难以理解、维护和重用。我们这样做会经常将我们的程序逻辑(动)融合到我们的持久性逻辑(名词)中,这可不是什么好的应用程序设计。另一个方案是要求客户端通过Java事务处理API(JTA)划定一个总的、大型的事务。这将使每个对实体bean的方法调用都属于同一个事务,要么全有、要么全无的形式。如果存款失败,那么提款也会被回滚,客户的存款是安全的。然而,这个稍有改进的方案仍然有不少缺陷:[高网络开销] 我们仍然需要处理6次网络调用,这会减慢性能(除非使用本地接口)。[弱并发性] 如果客户端距离服务器非常远(比如applet或应用程序与远程的EJB系统交互,甚至通过Internet或者防火墙的情况),事务就会持续很长一段时间,这会导致过度的(对象)锁定,增加出现冲突和死锁的几率,削弱其他客户访问同一个实体bean实例的并发性。[高耦合度] 我们的客户端直接与实体bean的API通信,这将使客户端与实体bean紧紧地连在一起。如果未来实体bean层需要修改,我们同时也需要修改客户端。[弱重用性] 执行"划账"用例的商务逻辑直接被嵌入到客户端,于是被"陷入"在客户端中。其他类型的客户端(Java应用程序、applet、servlet等等)不能重用这个商务逻辑。对于任何严谨的应用程序设计和部署来说,像这样将表示逻辑与商务逻辑混合起来的做法都是不可取的。[弱可维护性] 使用JTA会造成处理事务的中间件逻辑和应用程序逻辑搅在一起。将这两者通过明确声明的事务分开会更清晰,这样我们才能在不影响商务原则的情况下修改我们的中间件。[各个开发角色的弱独立性] 一个在大型项目开发中通常的做法是将实现表示逻辑的程序员(如servlet/jsp的程序员)的开发任务同实现商务逻辑/中间件的程序员(EJB开发人员)的开发任务分开来。如果商务逻辑出现在客户端/表示层,明确的任务划分是不可能的。如果实现商务逻辑的程序员和实现表示逻辑的程序员都需要在表示层开发,他们很容易出现冲突。我们这样讨论下来发现,我们需要一个服务器端的抽象作为中介来缓冲对实体bean的调用。会话bean正是基于此目的而设计的。所以说:[将实体bean层包装在一个称之为会话面板的会话bean层中。客户端应该只能访问会话bean而不能访问实体bean。]会话面板模式将传统的Facade设计模式应用到EJB:完全将服务器端的对象模块向客户层隐藏起来,并把会话bean层作为客户端访问的唯一途径。图1.2说明了此方案是如何改进应用程序架构的。会话面板模式更增加了通过强制在单个网络调用中执行一个用例所带来的好处,并提供了一个清晰的层来封装用于完成用例的商务和工作流逻辑。会话面板模式通常是作为一个无状态会话bean的层实现的(尽管这个模式也能通过有状态的会话bean来实现)。<图略>为了说明这个方案如何运作以及它带来的好处,我们再回到先前的例子。我们的"划账"用例的商务逻辑现在被放在会话bean中,这个会话bean有一个方法:transferFunds(userpk, acountpk, acountpk, amount)。BankTeller会话bean在Users和Bank Accounts上处理成组的操作,如图1.3所示。由于BankTeller会话bean与User和Account实体bean密切相关,它应该固定的通过本地接口访问实体bean,以减少执行用例所需的网络开销至仅仅一个调用(客户端调用BankTeller)。并且,所有对实体bean层的更新都应在由BankTeller发起的事务中处理,在其发布描述文件中几乎所有时候都设置TX_REQUIRED。这样做有效的将整个用例包装在单个事务中,保证了所有对实体bean的更新都在BankTeller的transferFunds方法的执行引发的事务中完成。<图略>会话面板模式是当今使用的最基本的EJB模式。它不仅提供性能上的好处,同时还代表了一种标准的EJB系统架构:在J2EE应用程序中用一个会话bean层将客户端和服务器端分隔开来。这些会话bean包含了针对应用程序中所有用例的方法,也包含了相应的商务逻辑。对BankTeller例子再进一步,很显然除了简单的"划账"用例之外还有很多其他的用例。通过使用会话面板模式,会话bean被创建以将相似的功能的用例组合到单个的bean中。于是我们可以向BankTeller增加其他的辅助银行操作(如提款、存款、查询)。在这个银行应用程序中的其他地方,其他目的的用例也可以组合到会话bean中。例如,每个银行都有一个信贷部,模拟信贷部的那些用例并非跟BankTeller的用例特别相关,所以这些用例可以被组合到LoanServices会话bean中。同理,一个银行应用程序可能还需要一个会话bean来封装与投资相关的用例。通过运用会话面板模式,这个银行应用程序的架构布局可以如图1.4所示。<图略>
      

  2.   

    会话面板模式运作得如此之好,以至于我们经常容易滥用它。我们不难发现误用会话面板模式的项目:[构建一个会话bean的万能类] 通常开发人员会把一个系统中所有的用例放在同一个会话bean中。这会造成臃肿的会话bean和减低的开发效率,因为所有开发人员都需要访问这同一个类。会话bean应该根据相关的用例划分成多个不同的bean。[将域逻辑放到会话bean中] 一个设计优良的面向对象的域模型应该包括应用程序中所有的商务/用例逻辑(福勒, 2001)。大多数会话面板模式的方法都应简单的传递到相应的实体bean,除非用例包含了需要跨bean操作的工作流逻辑,而这些bean可能是不直接相关的。[在面板中重复的商务逻辑] 随着项目的扩大,通常会话bean的方法会包含重复的代码,比如执行checkCreditHistory(检查信用历史)的逻辑,该逻辑可能是任意数量的用例的工作流的一部分。解决的方法是增加一个服务层(通过会话bean或者普通的Java类实现),这个服务层将这个独立于用例的商务逻辑封装起来,它对于用户来说是不可见的。当项目增大时,我们可以考虑定期进行重构,找出重复的逻辑并提取出来。以下是会话面板模式的优点:[低网络开销] 虽然会话bean层确实会增加调用会经过的层数,客户端现在可以仅仅通过一次网络调用实现转账,而不是6次调用。在服务器端,会话bean通过本地接口和实体bean通信,所以不会产生任何网络开销。甚至是对于那些只通过远程接口调用的实体bean,大多数应用服务器都会优化紧密相关的EJB之间的通信。[对商务逻辑和表示层清晰而严格的划分] 通过使用会话面板模式,执行商务逻辑需要的逻辑被完全包装在会话bean的方法之后。EJB的客户只需要关心表示层的问题而不用为了一组相关工作的完成调用超过一个的EJB的方法。这样就严格的将商务逻辑从表示层逻辑分离出来。[事务完整性] 我们的会话bean将所有与执行银行划账相关的逻辑封装在单个事务中。这样,会话bean就像一个事务面板一样执行,将事务本地化到服务器端,并保持相对短小。事务也被界定在会话bean的方法这个层次,能够通过发布描述文件进行配置。[低耦合度] 会话bean在客户端和实体bean当中起到缓冲的作用。如果实体bean层在今后需要修改,因为有会话bean层的间接性,我们能够避免修改客户端。[很好的重用性] 我们的BankTeller逻辑被封装到模块化的会话bean中,能够被任意类型的客户端访问(JSP、Servlet、应用程序、或者applet)。将应用程序逻辑封装到会话bean中意味着我们的实体bean可以只包含数据和数据访问逻辑,使它们能够被不同的会话bean甚至是在不同的应用程序中使用。[很好的可维护性] 我们应该在BankTeller会话bean的发布描述文件中明确的定义事务,而不是通过JTA编码到程序中。这样使我们的中间件和应用程序之间有清晰的界限,这就增加了可维护性,减少了出错的可能。[清晰的动-名词分隔] 在我们的应用程序中,会话bean层代表应用程序相关的用例或"动词",而实体bean代表了商务对象,或者说"名词"。这样的架构使得将用例从需求文档映射到实际的EJB层次结构变得十分容易。会话面板模式是EJB开发中的主要模式。它促使高效并且可重用的设计,同时清楚地将表示逻辑(客户端)、商务逻辑(会话面板)和数据逻辑(实体bean等)分隔开来。会话面板模式描述了一个用于实现任何用例的有用的体系结构;但是,如果一个用例从本质上讲是异步的,这时消息面板模式能提供一个更好的方案。
    [相关模式]消息面板
    数据传输对象
    会话面板(Alur, et al., 2001)
    会话面板(MartinFowler.com)
      

  3.   

    hehe,肯定是毕业设计需要。
    接分分~~