最新EJB设计模式中文版之Session Facade(会话外观)

    技术2022-05-11  160

    session facade

    一个EJB客户端为了完成一个用例需要执行一个商业逻辑。EJB客户端怎样才能在一个事务(transaction)和一个大批(bulk)网络调用中执行一个用例的商业逻辑呢?为了执行一个典型的用例的商业逻辑,多个服务器端对象(如session或entity bean)通常需要被存取和可能的修改。问题是session和entity bean的多个细粒度(fine-grained)调用增加了多次网络调用(而且可能是多个事务的)的网络开销(overhead),并且导致可维护性差的代码,因为数据存取和工作流/商业逻辑在客户端之间分散了。考虑一个在线银行情景,一个servlet接受请求来从一个账户向另一个账户传输存款,作为一个Web客户端。在这个情景下(像图1.1所示),一个servlet必须检查来保证用户是授权了的,从一个银行账户entity bean取出存款,并且把它存入另外一个银行账户entity bean。当执行一个entity bean的home和remote interface,这个方法在重负荷时将无法伸缩(scale),因为整个情景(scenario)需要至少6个网络调用:3个寻找合适的entity bean,还有三个实际的传送存款。还有,因为entity bean是事务性的生物,每个对实体的调用需要一个分离的服务器端的事务,需要通过应用服务器的数据存储和维护来和远程实体同步。更糟的是这个方法无法保证客户的钱的安全性。如果在存钱时出错了,客户的钱将已经被取出,并且他的钱将会丢失。用户授权检查,取钱,和存钱完全分离的运行,并且如果存钱失败,取钱将不会回滚(roll back),结果是不连续的状态。这里的问题是:当entity bean的方法被直接调用,每个方法调用是一个分离的工作单元,并且是一个分离的事务。一个解决方案是在我们的entity bean中加入额外的逻辑,来在一个单独的客户调用中完成许多操作。这个解决方案引入了维护问题,因为我们的entity bean层将不能被应用到许多不同的方式上。如果我们在每次需要性能增强时增加应用逻辑到我们的entity bean上时,我们的entitybean将很快变得臃肿和难于理解,维护和复用。我们有效的将我们的应用逻辑(动词)和我们的持久化逻辑(名词)融合起来,但这是差的应用设计。另一个方法是为我们的客户端划分一个聚合,通过JTA的大的事务。这将每个entity bean的方法调用工作在一个相同的事务之下,在一个"全部或没有"(all-or-nothing)的风格下。如果存钱失败,那么取钱将会被回滚(roll back)并且用户的钱将会变得安全。然而,这个改进的解决方案也有很多缺点:1.高的网络开销。我们将有6个网络调用,将会降低性能。(除非我们使用local interface)。2.差的并发性。如果客户端离服务器很远(如一个applet或application和远程的EJB系统交互,甚至可能通过internet或一个防火墙),这个事务将会持续一个很长的时间。这将导致超额锁定(excess locking),增加冲突和死锁的可能性,并且降低了其他客户端存取同一个entity bean实例的并发性。3.高耦合。我们的客户端直接写一个entity bean的API,这将使客户端和entity bean紧密的耦合在一起。如果entity bean层需要在将来变化,我们也必须改变客户端。4.差的可复用性。执行“传送存款”的用例的商业逻辑直接被嵌入到客户端。那么它将被有效的套在了那个客户端中。其他类型的客户端(Java application,applet,servlet,等等)不能重用这个商业逻辑。这个把表示逻辑和商业逻辑混在一起是一个差的为任何重要的发布的应用设计。5.差的可维护性。JTA的使用导致完成事务的中间件逻辑和应用逻辑交织在一起。通过宣称(declarative)事务分离这两个会更干净,所以我们能拧(tweak)和调(tune)我们的中间件,而且不会影响我们的商业规则。6.差的开发角色的分离。一个通用的在大型项目的实践把表示层逻辑程序员的开发任务(如serlet和jsp开发者)和商业逻辑/中间件程序员(EJB开发者)分离开来。如果商业逻辑和客户端/表示层一起编码,一个清楚的角色区分是不可能的。商业逻辑和表示逻辑程序员将踩着各自的脚尖,如果同样在表示层编程。我们的讨论的结论(takeaway point)是我们需要一个服务器端的抽象作为entity bean的中介和缓冲。session bean正是为这个设计的。因此:   用一个叫做session facade的session bean层来封装entity bean层。客户端应该只能存取sessionbean,不能存取entity bean。session facade模式把传统的facade模式的好处应用到EJB,通过完全对客户端隐藏服务器上的对象模型,通过用session bean层作为客户端的单独存取点。图1.2描绘了架构通过这个方法能被改进。session facade模式还通过在一个网络调用的增强的用例的执行和提供一个干净的层来封装完成这个用例的商业和工作流逻辑带来好处。session facade通常作为无状态session bean来实现。(虽然这个模式可以用有状态session bean来实现。)为了描绘这个paradigm怎样工作和这个paradigm带来的好处,让我们用我们先前的例子。我们用来的传输存款的用例的商业逻辑现在将在一个session bean中替代,这个session bean有一个叫做TransferFunds(userpk,accountpk,accountpk,amount)的方法。那个Bank Teller session bean因此完成大批(bulk)对Users和Bank账户的操作,如图1.3所示。因为Bank Teller session bean和User和Accountentity bean共存,它应该被hard-coded来和entitybean通过local interface通信,因此把需要执行那个用例的网络开销减小到一个调用(从客户端到Bank Teller的调用)。同样,所有对entity bean层的更新应该在Bank Teller所发起的事务中完成,在它的deployment discriptor中定义,几乎总是,用TX_REQUIRED的设置。这样有效的用一个事物包装了整个用例,确保所有对entity bean的更新都在Bank Teller的transferfunds方法所发起的事务中完成。session facade模式是今天使用中的最基础的EJB模式(这就是为什么它是这本书的第一个模式)。它不但提供性能好处,也建议了为EJB 系统分配(systems-partitioning)你的J2EE应用的标准架构,客户端和服务器被一个session bean层所分离,这个session bean的方法映射到(并且包括商业逻辑)所有的应用中的用例。进一步用Bank Teller例子,在bank应用中明显有比传输存款更多的用例。使用session facade模式,session bean将被创建来分组用例,使相似的函数在一个bean中。因此我们可以增加其它辅助(ancillary)银行操作到Bank Teller(如withdrawFunds,depositFunds,getBalance())。另外在banking应用中,为了不同目的的用例也可以分组到一个session bean。例如,每个银行有一个存款部门(loans department)。需要去建模存款部门的操作的用例和Bank Teller的用例没有关系。;所以,它们将分组成一个LoanService session bean。相似的,一个banking应用将也需要一个session bean来封装和投资(investment)相关的用例。使用sessionfacade模式,这个baking应用的架构铺设(architectural layout)将会如图1.4。session facade模式工作得如此之好,以至于常常它很容易被滥用。很通常能发现sessionfacade被误用的项目:1.创建一个session bean巨类(God-class)。常常开发者把系统中所有的用例都放在一个session bean中。这导致臃肿的sessionbean并降低开发生产力,因为所有的开发者都需要用这一个类。session bean应该被分成相关的用例的组群(house groupings)。2.把领域(domain)逻辑放在session bean中。一个设计得好的OO领域模型应该包括所有的你的应用中的商业/用例逻辑(Fowler,2001)。大多数session facade方法应该只是代理(delegate)合适的entity bean,除非用例包含需要跨不同bean而且不是直接有联系的工作流(workflow)逻辑。3.跨facade的商业逻辑的重复。随着项目的增长,常常session bean方法包含重复代码,如对checkCreditHistory的执行逻辑,可能是任何数量的用例的工作流的一部分。这个解决方案是增加一个服务层(作为一个session bean或普通java类来实现),来封装这个可重用,用例独立(use-case-independent)的商业逻辑。这个服务层是对客户端隐藏的。当项目的体积变大时,用常规重构(refactoring) sessions(重复逻辑被发现和抽出(extracted))是很有用的。下面是session facade模式的好处:1.低网络开销。当session bean层增加一个层来调用,客户端现在能只在一个网络调用中传输存款,而不是6次网络调用。在服务器上,session bean和entity bean通过localinterface来调用,从而不导致任何网络开销。即使entity bean只被用做remote interface,大多数应用服务器将优化共存(collocated)的EJB之间的通信。2.干净和严格的商业逻辑和表示层之间的分离。通过使用session facade,需要去执行商业逻辑的逻辑完全被封装在session bean的方法之后。EJB客户端无需关心表示层的事情,并且为了一个单位的工作完成无需执行多于一个方法。这严格的将商业逻辑从表示逻辑分离。3.事务集成。我们的session bean封装了所有的逻辑来完成银行传输在一个事务中。sessionbean因此作为一个事物facade,对服务器端定位事务,并且保持它们短小。事务也在session bean方法层次被改进(demarcated)了,通过deployment descriptor可配置。4.低耦合。客户端和entity bean之间的请求被session bean缓冲了。如果entity bean层需要在将来变化,我们能避免改变客户端,因为有session bean的间隔(indirection)。5.好的可重用性。我们的bank teller逻辑是被封装到一个模块化的session bean中,能被任何类型的客户端(JSP,servlet,application,或applet)存取。封装到sessionbean的应用逻辑意味着我们的entity bean能只包含数据和数据存取逻辑,让它们可以跨session bean在同一个或者甚至不同应用中可复用。6.好的可维护性。一个人应该宣称性(declaratively)的在Bank Teller session bean的Depolyment Discriptor中定义事务,而不是通过JTA编程式(programmatically)的方法。这让我们有一个干净的对中间件和应用逻辑的分离,增加可维护性并且减少出错的可能性。7.一个干净的动词-名词分离。session bean层建模了特定应用用例,我们应用中的动词,而entity bean建模了商业对象,或“名词”,在我们的应用中。这个架构让我们很容易从我们的需求文档映射到一个真实的EJB架构。session facade模式是EJB开发中的订书钉(staple)。它加强了高效率和可重用性的设计,和清楚的分离了表示逻辑(客户端),商业逻辑(session facade)和数据逻辑(entity bean,等等)。session facade描述了一个有用的实现任何类型用例的架构;然而,如果在自然中用例是异步的,Message facade模式提供了一个更有伸缩性的方法。相关模式:Message FacadeData Transfer Objectsession facade(Alur,et al.,2001)session facade(MartinFowler.com)


    最新回复(0)