使用 Java EE 实现松耦合的SOA应用程序

ZDNet软件频道 时间:2009-02-04 作者: | IT专家网 我要评论()
本文关键词:SOA 松耦合 Java EE JAVA
 基于 Web 客户端的 HttpServlets 或富(“胖”)客户端的 Swing 应用程序。但我们曾听说面向服务的体系结构都是与松耦合有关的 。
 问题:太过于关注 SOA 中的会话和实体

  亲爱的 EJB 倡导者:到目前为止您的专栏全部都是关于服务的会话和实体 EJB,它对于直接连接 JAVA 应用程序是很重要的,例如基于 Web 客户端的 HttpServlets 或富(我们不喜欢说“胖”)客户端的 Swing 应用程序。但我们曾听说面向服务的体系结构都是与松耦合有关的 。这不就意味着要尽可能地使用 SOAP 来提供使客户端和服务器应用程序能够独立运行的语言中立性和异步协议?换句话说,为什么您对 JMS 和消息驱动 Bean 讨论得不多呢?

  署名:Feeling Disconnected

  松耦合有许 多方面要考虑

  亲爱的 Disconnected:EJB 倡导者关注的是应用程序的服务层,而对客户端介绍得很少, 因为我对古谚语形式追随功能 (form follows function) 深信不疑。

  其原因在于,许多进行 SOA 的项目之所以失败,是因为 它们没有首先建立定义服务的良好模型就开始着手实现细节。

  这种倾向相当正常,因为我在 SOA 项目中接触到的大多数人都是架构师 和编程人员,他们知道棘手的始终是在细节上,想要尽快解决它们。所以,一旦我们认同好服务的特征是粗粒度、无状态、可通过中介传递和 适应的(请参阅 Is it ever best to use EJB components without facades in service oriented architectures?),很明显带有数据传输对象的会话 Bean 就会在实现 中扮演重要角色。

  但上期专栏介绍了使用实体 Bean 及其 Home 方法代替会话 Bean 的可能性,从而使人们对会话 Bean 是否真的是 必需的产生了疑问。图 1 显示了同时使用的两种方法。

  图 1. 用有待使用的会话和实体 EJB 实现的服务

  图 1 显示了当使用传递过去的会话 Bean 时,纯实体方法(自 EJB 2 开始可用)如何才能有更少的组件和更短的路径长度。其中使用绿色框表示 客户端,蓝色框表示各种接口和 Facade 类。橙色框是最常访问的实体 Bean。框和框之间使用双向箭头连接,箭头标有在组件之间通信所使用 的协议;蓝色箭头表示相同 JVM 中的 JAVA 调用,红色箭头表示远程连接(在本例中使用 RMI/IIOP)。为了表示端到端的流向,对流程箭头 进行编号,其中 A1-A10 表示从 JAVA 客户端经过会话 Bean 到实体和返回的流程,B1-B4 表示从客户端直接到实体 Bean 和返回的流程。

  客户端用于检索服务接口的编程模型也很简单,虽然在图中没有表示出来。检索会话 Bean 接口需要在 JNDI 上下文中查找会话 Home 并用它创建一个会话;实体 Home 仅仅需要一次查找,其方法可以直接调用而不需要创建对 EJB Object 的引用。以下两段代码示例显示了它 们之间的区别。

  清单 1. 定位和调用远程会话 EJB 方法

Context initCtx = new InitialContext();
Object obj = initCtx.lookup("JAVA:comp/env/ejb/OrderEntry");      
OrderEntryHome home = (OrderEntryHome)PortableObjectRemote(obj,
 OrderEntryHome.class);      
OrderEntry ref = home.create();
// Method must be invoked on
   a session referenceCustomerData data =
       ref.getOpenOrderForCustomercID);

  清单 2. 定位和调用等效远程实体 EJB Home 方法

Context initCtx = new InitialContext();
Object obj = initCtx.lookup("JAVA:comp/env/Customer");
CustomerHome ref = (CustomerHome)
                  PortableObjectRemote(obj, CustomerHome.class);
// Note how the method is invoked directly  
CustomerData data = ref.getOpenOrder(cID);

  图 1 和相关的代码示例显示了 Java EE 编程模型的真 正好处,不管您是否选择使用实体 Home 方法。编程模型逐渐改进并提供向后兼容。简而言之,您的最佳实践能够得以发展而不必强制 更改现有的应用程序。另外,JNDI 上下文提供了一个不容忽视的松耦合相关方面:实现独立性。

  会话或实体 EJB 组件的远程接口提供了位置独立性。使用远程接口使得在相同的 JVM 中部署客户端应用程序和服务组件成为可能 ,其中它对系统(例如使用 HttpServlets 的 Web 应用程序)的响应时间、吞吐量和可维护性目标有意义。图 2 显示的正是这样的配置,其 中企业质量应用服务器(如 IBM® WebSphere® Application Server)在联合部署了客户端和服务组件时“短路”远程接口以使用 JAVA 并按引用传递(不管服务实现为实体 Home 方法还是会话 Bean)。流程 A1-A6 显示了与服务组件联合部署的 HttpServlet 的使用。流 程 B1-B4 显示了它如何被远程富客户端 Java EE 应用程序重用。

  图 2. 部署到本地 Web 应用程序和远程富客 户端的服务

但这听起来像是您已确定松耦合的最重要方面是语言中立性和异步操作。并且您认为需要异步操作会使得必须在服 务器端使用消息驱动 Bean (MDB) 和 JMS。

  在实现 MDB 时,许多编程人员使用的方法是通过其远程接口调用表示服务的 EJB 组件,以 使上述位置独立性最大化。然后,不管服务实现是远程还是本地部署,MDB 的目的都是作为简单的适配器,将 MQ 层连接到承载服务的 EJB 容 器。JMS 可能由异步客户端应用程序(如果它是 JAVA)或 MDB 使用(通常用于应答队列)。图 3 显示了服务实现的另一个输入通道的这一配置。仍然有太多选项要选择

  亲爱的 EJB 倡导者 :

  谢谢。

  我以前不认为像 JNDI 这样的服务和远程接口会提供松耦合。我还可以了解如何将 SOAP 和 MQ 的概念“紧耦合 ”(按照您提到的方法),以及应该如何尽可能将它们分开。所以将解析和生成 SOAP 消息看作由 Web 服务 Servlet 和 MDB 重用的服务本身 是很有意义的。

  但谢谢,我不要这样。

  在这次讨论之前,SOA 看似非常简单:每个服务都公开一个 SOAP/MQ 接口。现在看起来 有好多选择要考虑,并且既然将 SOAP 消息的解析和生成看作服务,那么为什么不想建立一个独立的会话 Bean 来封装它们以便如图中所显示 的那样进行重用呢?

  再次打扰您,我还是:Still Disconnected

  并非一切都是服务:要使用业务模型加以判定

  亲爱的 Disconnected:这次讨论是当过快要着手实现细节时会出现的 情况的一个很好的例子。EJB 倡导者专栏 Which type of EJB component should assemble the data returned by a service? 非常重要,因为它描述了一种定义服务的自顶向下方法,这种方法将服务直接与业务流程模 型相关联。这里总结这种方法的基本细节:

  开发一个业务流程模型,显示重要域对象的生命周期中的主要里程碑:

  •   我们使用状态转换关系图来描述这一模型,其中状态代表里程碑,转换代表促使变成该状态的事件。转换可以看作应用程序所 提供的服务(有关示例请参见图 5)。
  •   我们使用 UML "Actor" 符号来扩展状态转换关系图,以显示当处于该状态时对象的所有者 。状态的所有者负责发起转换,从而驱动应用程序的安全模型(也请参见图 5)。
  •   对于业务流程中的每个状态,我们也对每个需要 支持转换动作的域对象的属性和它们之间的关系进行建模。我们通常使用的符号是 UML 类关系图(有关示例,请参见图 6)。为每个状态建立 独立的关系图可以让我们随时对变化的对象“形状”进行建模。这些关系图驱动持久性数据。

  开发一个用户界面流程模 型,显示在典型“会话”期间来自业务流程的给定参与者如何与系统相交互。

  •   与业务流程模型一样,我们也使用状态 转换关系图,其中状态代表屏幕和对话框,而转换代表实际的 UI 事件,如选择菜单项和按下按钮。根据业务流程转换指定与转换相关的动作 。
  •   还是和业务流程模型一样,我们构建一个类关系图来显示必须在每个状态中可见的数据以支持各种选择。这意味着该数据必须可 以从用户输入派生,并以自顶向下的方式驱动服务上的读取操作。
  •   与业务流程模型不同,我们不需要用 Actor 符号扩展状态关系 图,因为关系图本身可以视为单个用户角色的“生命中的一天 (day in the life)”。

  图 5. 显示订单生命周期的状态转换关系图示例

  图 6. 显示 open 订单“形状”的类关系图示例

  这种综合方法可以确保:

  •   将正确的操作分组到一个服务(与业务流程生命周期中的一个状态相关联的所有转换和 read 方法)。
  •   每个服务 的用途很好理解(根据相关业务对象来指定动作)。
  •   调用服务需要的前置条件和会产生的后置条件是相通的(当前状态和可选的监 护、以及下一状态都是通过转换指定的)。
  •   标识了负责调用服务的用户角色(参与者与每个状态相关联)。

  不管是否实现,方法签名都不会提供此信息,但此信息对于好的 SOA 来说是很关键的。否则,编程人员将陷入另一种倾向:一旦有怀疑,就 再次构建。因为 SOA 的开发成本比较高(要为图 4 所示的完全松耦合提供各种中介器和适配器),所以这种反对重用的倾向可能会导致 获得好处最少。

  对您关于简单性的答复中提出的问题的回答是,此信息一点都没有强制您以某种方式公开接口,EJB 倡导者知道简单只 存在于旁观者眼中。如果您想要使服务开发人员不必进行选择,只需为每个服务提供图 5 中所示的所有“蓝色”组件即可:

  •   远程服务接口,用于提供同步 Java EE 客户端访问服务操作的位置独立性。
  •   与每个操作相关联的 MDB,通过遵循 JMS 的 MQ 实现 来提供异步非 JAVA 客户端访问。您可以选择编写此 MDB 或不同的 MDB 以期待 JMS 客户端的 JAVA 消息(从而避免 HTTP 解析开销)。
  •   与每个操作相关联的 Web 服务 Servlet,用于提供同步 SOAP over HTTP 客户端访问。

  因为有人会担心这种方 法将生成大量未使用的组件,所以另一种简单的方法是,应用 EJB 倡导者喜欢的内容来调用面向客户端的体系结构 (COA);以对客户端最自然 的方式给它们提供使用服务正好需要的内容。

  这种 COA 方法需要考虑业务流程和 UI 模型的细节,以便为每种方法挑选最可能的候选 者。例如:

  •   业务流程生命周期中的状态之间的转换很可能是异步服务的候选者,因为它们将是相关域对象的“所有者”变体。 例如,在 open 订单应用程序(我们在上述示例中调用此 OrderEntry)中,submit 方法可以简单地将订单的状态更改为“submitted”,并发 送一条 JMS 消息来将其复制到已提交订单应用程序中(我们将这称为一次 OrderFulfillment)。
  •   状态间的转换通常应该是同步的 ,因为所有者没有改变。举个例子来说明为什么这些操作不应该是异步的,设想一下,如果您进入一位书商的 Web 应用程序,还必须轮询或等 待发布-订阅事件来显示目录或将物品添加到购物车中!对于想要通过异步通道使用伪同步方式的读者,请查阅 Bobby Woolf 关于设计消息传 递系统的书籍。
  •   只有对于没有相关的非 JAVA 客户端和服务的集成场景,才提供 SOAP over HTTP 或 MQ。

  使用 COA 方法,可以“准时 (just-in-time)”开发组件,这就是 EJB 倡导者喜欢推荐它的原因。

  对您的问题(为什么不将所有的东西 都看作是服务,甚至是与中介器和适配器相关联的转换)的回答的最后一点是:简单的回答超出了“过犹不及”这一事实。在开发 SOA 或 COA Java EE 应用程序时,最好将服务视为业务流程模型上的操作。服务与应用程序的功能需求有关。中介和相关联的转换与非功能需求有关,例 如可靠性、可用性、有效性、可维护性和可移植性。如果您将中介或相关联的转换视作第一个类服务,则最终将使应用程序的真实用途变得模 糊。

SOA

松耦合

Java EE

JAVA


百度大联盟认证黄金会员Copyright© 1997- CNET Networks 版权所有。 ZDNet 是CNET Networks公司注册服务商标。
中华人民共和国电信与信息服务业务经营许可证编号:京ICP证010391号 京ICP备09041801号-159
京公网安备:1101082134