JBI 规范 1.0


JBI 规范 1.0 Java Business Integration Specification 1.0 Made By Juset 2006.12 2 目录(Contents) 1 前言(Preface)............................................................................................................. 5 2 介绍(Introduction)...................................................................................................... 5 3 概述(Overview) ......................................................................................................... 5 3.1 定义(Definitions)............................................................................................. 7 3.2 基本原理与假设(Rationale & Assumptions)....................................................... 9 3.3 目标(Goals) .................................................................................................... 9 3.4 与其他规范技术的关系(Relationship to other Specifications and Technologies) ....10 3.5 角色(Roles)....................................................................................................10 3.5.1 引擎开发者(Engine Developers)............................................................11 3.5.2 绑定开发者(Binding Developers) ..........................................................11 3.5.3 JBI 系统提供者(JBI Environment Providers) ..........................................11 3.5.4 J2EE™ 平台提供者(J2EE™ Platform Providers)....................................11 3.5.5 JBI 应用开发者(JBI Application Developers)..........................................12 4 JBI 系统架构(Architecture of the JBI Environment) ......................................................13 4.1 基于 WSDL 的消息模型(WSDL-based Messaging Model) .................................13 4.1.1 抽象服务模型(Abstract Service Model)..................................................14 4.1.2 具体服务模型(Concrete Service Model) .................................................15 4.2 规格化消息(Normalized Message) ...................................................................16 4.3 JBI 顶层架构(High-Level Architecture) ............................................................16 4.4 规格化消息交换(Normalized Message Exchange)..............................................17 4.5 管理(Management) .........................................................................................19 4.5.1 组件安装(Component Installation) .........................................................19 4.5.2 生命周期管理(Life Cycle Management) .................................................19 4.5.3 服务单元部署(Service Unit Deployment) ...............................................20 4.6 组件框架(Component Framework)...................................................................20 4.7 规格化消息路由(Normalized Message Router)..................................................20 4.8 组件(Components)..........................................................................................21 4.8.1 服务引擎(Service Engines) ...................................................................21 4.8.2 绑定组件(Binding Components) ............................................................21 4.9 举例(Examples)..............................................................................................21 4.9.1 单向消息适配(One-way Message Adapter) .............................................22 5 规格化消息路由(Normalized Message Router) ............................................................24 5.1 关键概念(Key Concepts).................................................................................24 5.1.1 服务的消费者和提供者(Service Consumers and Providers)......................25 5.1.2 规格化消息(Normalized Message).........................................................25 5.1.3 传输通道(Delivery Channel) .................................................................26 5.1.4 运行时端点激活(Run-time Endpoint Activation) .....................................26 5.1.5 服务调用和消息交换模式(Service Invocation and Message Exchange Patterns) 27 5.1.6 消息交换(Message Exchange)...............................................................28 5.1.7 端点(Endpoints)...................................................................................31 5.2 消息交换的构成(Element of a Message Exchange) ............................................32 5.2.1 交换概要(Exchange Summary)..............................................................33 3 5.3 规格化消息(Normalized Message) ...................................................................34 5.3.1 规格化定义(Normalization Defined) ......................................................34 5.3.2 规格化消息的结构(Structure of a Normalized Message)...........................34 5.3.3 处理方法(Processing Methods)..............................................................35 5.3.4 二进制数据(Binary Inclusion) ...............................................................35 5.3.5 WSDL1.1 的支持(Support for WSDL 1.1) ..............................................35 5.4 NMR 设计(NMR Design) ................................................................................35 5.4.1 激活(Activation) ..................................................................................35 5.4.2 交换消息(Exchanging Messages)...........................................................37 5.4.3 消息交换路由(Routing Message Exchange) .......................................42 5.4.4 使用动态端点引用 (Use of Dynamic Endpoint References).....................45 5.5 NMR API(NMR API)......................................................................................48 5.5.1 消息 API(Message API)........................................................................48 5.5.2 服务 API(Service API)..........................................................................54 5.5.3 查找激活端点(Querying Activated Endpoints) ........................................64 5.5.4 端点引用 API(Endpoint Reference API) .................................................65 5.5.5 应用举例(Usage Examples)...................................................................67 5.5.6 服务提供者元数据(Service Provider Metadata).......................................72 6 管理(Management)....................................................................................................74 6.1 概述(Overview)..............................................................................................74 6.2 关键概念(Key Concepts).................................................................................75 6.2.1 组件安装(Component Installation) .........................................................75 6.2.2 共享库安装(Shared-library Installation)..................................................75 6.2.3 部署(Deployment)................................................................................75 6.2.4 部署生命周期(Deployment Life Cycle) ..................................................78 6.2.5 组件生命周期(Component Life Cycle) ...................................................78 6.2.6 类的加载(Class Loading) ......................................................................79 6.2.7 使用 JMX(Use of Java Management Extensions) .....................................79 6.2.8 使用 Apahca Ant 编写脚本(Use of the Apache Ant for Scripting) ..............80 6.3 包装(Packaging).............................................................................................80 6.3.1 安装和部署描述符(Installation and Deployment Descriptors)...................80 6.3.2 安装包(Installation Packaging) ..............................................................88 6.3.3 服务集合包(Service Assembly Packaging)..............................................89 6.3.4 服务单元包(Service Unit Packaging) .....................................................90 6.4 服务安装(Installation Service) .........................................................................90 6.4.1 共享库安装(Shared Library Installation).................................................90 6.4.2 组件安装(Component Installation) .........................................................91 6.4.3 组件卸载(Component Uninstallation) .....................................................94 6.5 组件生命周期(Component Life Cycle) .............................................................94 6.6 服务部署(Deployment Service)........................................................................98 6.6.1 服务单元部署过程(Service Unit Deployment Processing) ........................99 6.6.2 服务集合撤销部署过程(Service Assembly Undeployment Processing)....100 6.6.3 连接元数据处理(Connection Metadata Handling)..................................100 6.7 服务单元生命周期(Service Unit Life Cycle) ...................................................102 4 6.8 服务集合生命周期(Service Assembly Life Cycle).......................................103 6.9 MBean 状态和结果字符串(MBean Status and Result Strings)...........................104 6.10 Ant 脚本支持(Ant Script Support)..................................................................107 7 组件框架(Component Framework)............................................................................108 7.1 组件提供的管理功能(Component-Supplied Management Functions) .................109 7.1.1 引导程序(Bootstrapper)......................................................................109 7.1.2 组件接口(Component Interface) ..........................................................109 7.1.3 组件生命周期(Component Life Cycle) ................................................. 110 7.1.4 服务单元管理(Service Unit Management) ............................................ 112 7.2 JBI 环境的特性(JBI-Supplied Environment Features)....................................... 113 7.2.1 组件上下文(Component Context) ........................................................ 113 7.2.2 安装(引导)(Installation[Bootstrap]) ................................................. 115 7.2.3 日志(Loggers).................................................................................... 116 7.3 类的 加载(Class Loading)............................................................................. 117 7.3.1 类和资源的加载方式和加载器排序(Class and Resource Loading Styles and Loader Ordering).............................................................................................. 117 7.3.2 共享库(Shared Libraries) .................................................................... 118 7.3.3 执行类加载器(Execution Class Loader)................................................ 119 7.3.4 引导类加载器(Bootstrap Class Loader) ................................................121 7.4 出错提示(Error Indication) ............................................................................123 5 1 前言(Preface) 2 介绍(Introduction) 3 概述(Overview) JBI 定义了一种通过插接组件间交互传递中间消息(Mediated Message Exchange)的方式构建集成的架构方案。JBI 中定义的消息交换模型基于 WSDL2.0 规范(或 WSDL1.1)。 图 1 JBI 插件系统 图 1 展示了抽象层次的 JBI 插接组件概念,JBI 为插接组件提供了特定的交 互接口,插接组件也为 JBI 系统提供了特定的交互接口,组件与组件之间并不直 接进行交互,相反如图 2 所示,JBI 作为组件之间消息交换的中介。参与数据交 换的组件间的分离对于解耦服务提供者和服务消费者是至关重要的,这也是一般 的 SOA 架构,特别是集成解决方案所期望的。这种方式提供了很大的灵活性,因 为消费者和提供者之间的纠缠达到了最小化,同时对于 JBI 实现中的消息处理和 监控也是很重要的。同时要注意,因为这种处理模式中固有的异步特征使得提供 者和消费者之间从不共享一个线程,从而有助于保持组件间的松耦合。 6 图 2 中间消息交换:消息序列图 在这种基于 WSDL 的面向服务的架构模型中,JBI 插接组件负责提供和消费服 务。通过提供服务,一个组件为其他组件甚至是它自己提供了一种或多种处理功 能(function),这些功能在 WSDL2.0 模型中定义为操作(operation),参与 一个或多个消息的交换。WSDL 规范中定义的四种基本的消息交换模式(Message Exchange Patterns,简称 MEPs)清楚地定义了上述操作在执行过程中消息的交 换顺序。这四种消息交换模式是 JBI 组件(消费者和提供者)之间进行交互的基 础。 JBI 组件提供的任何服务都是由组件使用 WSDL1.1 或 2.0 规范进行描述的, WSDL 为基于 XML 的消息交换提供了一种抽象的,独立于特定技术的服务模型。 WSDL 也为服务消费者和 JBI 环境本身提供了一种声明额外的服务元数据的机制, 组件可以通过 JBI 环境查找可用的 WSDL 描述的服务。 如图 1 所示,JBI 组件插接在一个称为�JBI 框架�(JBI framework)的环境 中。这些组件可为来自第三方的终端用户所用,尤其在应用系统集成时遇到问题 时,它们可以提供一些通用的或标准的功能。 这些组件可以分为两种不同的类型: · 服务引擎(Service Engine [SE])服务引擎既为其他组件提供了业务逻 辑和数据转换服务,同时也消费这些服务。服务引擎可以集成基于 Java 的应用(和其他资源)或提供了 Java API 接口的应用。 7 · 绑定组件(Binding Component [BC])绑定组件为 JBI 环境以外的服务 提供了连通性,这些外部的服务可能包括通信协议或企业信息系统 (Enterprise Information System)提供的服务(EIS 资源)。绑定组件 可以集成使用 Java 环境不能提供的远程访问技术的应用(或其他资源)。 服务引擎和绑定组件可以是服务提供者,服务消费者或两者兼具。服务引擎 和绑定组件基于合理的架构原则,但两者之间的差别完全由实际应用决定。把业 务处理逻辑同通信逻辑分离降低了实现的复杂度并提高了灵活性。 JBI 不仅为消息系统提供了组件互用性,同时也定义了一个基于 JMX(Java Management eXtensions)的管理框架。JBI 为以下功能提供了标准的管理机制: · 组件的安装 · 组件生命周期的管理(启动/停止等) · 组件服务描述信息(Service Artifacts)的部署 最后要说明的一点是,JBI 组件也可以看作一种容器,通过部署服务描述信 息添加新的服务消费者或服务提供者逻辑。例如,一个提供基于 XSLT 转换服务 的服务引擎可以部署 XSLT 样式表,从而添加新的转换操作。这种为特定组件添 加功能服务描述信息的过程称为�部署�(Deployment),用于区分组件的安装。 JBI 将一组部署描述信息及其相关的元数据的集合称为服务集合(Service Assembly)。这些服务描述信息及其关联元数据集在一些文献中称为合成服务描 述符(Composite Service Description [CSD])。 3.1 定义(Definitions) JBI 定义的不是一个传统的应用程序模型,相反地, JBI 通过将插接组件抽 象为服务提供者和服务消费者而与面向服务的架构紧密结合来构建企业应用。开 发人员使用该规范中定义的 APIs 和 SPIs 开发插接到 JBI 环境中的服务引擎和绑 定组件。 服务引擎(SE)是指提供业务逻辑处理,数据转换服务等的插接组件。 8 服务引擎根据其提供的功能可以有多种形式。特别的,一些 SE 可作为处理 容器,为用户提供特定的开发模型,例如: · 一个 XSLT XML 转换引擎可以支持多种转换形式,应用开发接口就是 XSLT 语言本身; · 对于一个 WS-BPEL 2.0 业务处理执行引擎,应用开发接口就是 WS-BPEL; · 对于一个 EJB 容器,API 就是符合特定 EJB 规范的 Java。 绑定组件通过提供通信协议处理功能,使得 JBI 组件可以访问 JBI 环境以外 的外部系统提供的远程服务,同时外部远程服务消费者可以访问 JBI 环境内部提 供的服务。通信协议可以根据系统集成需求的不同而不同,典型的例子包括: · 基于 HTTP 的 SOAP[http://www.ws-i.org/Profiles/BasicProfile-1.1.html]; · JMS/MOM[http://jcp.org/aboutJava/communityprocess/final/jsr914/ index.html] · AS1/AS2 EDI [http://www.ietf.org/html.charters/ediint-charter.html]通信协议 栈。 一个绑定组件可能会选择实现一种或多种通信协议,提供到 SE 的连通性服 务,使 SE 把它们的服务发布给远程消费者,同时它们也消费远程服务。 JBI 的各种用户可以扮演几种不同的角色: · 集成架构师(Integration Architect)设计解决系统集成问题的整体思 路,包括选择提供连通性和业务逻辑的 JBI 组件。 · 集成技术员(Integration Technologist)设计解决某个集成问题的具体 服务,并对这些服务在 JBI 系统中的集成进行配置。 · 系统管理员(System Administrator)安装、配置、监控和调整 JBI 系统, 提供设计好的集成服务。 9 · JBI 组件开发者(JBI Component Developer)JBI 组件可以由用户或是第 三方来创建。无论谁来创建,JBI 插件的开发者必须提供符合本规范定义 的具体要求的 Java 组件。 3.2 基本原理与假设(Rationale & Assumptions) 本规范的基本原理立足于以下几个关键假设、经验数据 、传闻和业务需求。 · J2EE�平台提供者越来越把 Web 服务作为中心而不是作为其产品所使用 的辅助工具。 · Web 服务标准的革命使得在服务集成领域越来越需要大量的新型开发人 员,他们需掌握的将不再主要是过程化语言,而是新兴的标记语言。 · 能够支持服务合成语言,这主要是因为 WSDL 可以描述抽象业务消息的含 义,尤其是 WSDL 所定义的消息。 · 建立规格化(业务)消息的通用抽象视图,可以将组件特定的应用程序模 型(用于设计和开发业务逻辑)从支持这些逻辑的通信基础结构中剥离出 来。 3.3 目标(Goals) 以下是本规范的基本目标: · 为服务引擎和绑定组件的开发者建立一套标准的 SPI,即 JBI 组件。 · 抽象的协议无关的消息交换(protocol-neutral Message Exchange)和规 格化消息(Normalized Message [NM])。 · 提供一套标准的 JBI 组件间消息交换机制。 · 建立一个标准来封装 JBI 组件,并为这些组件部署服务。 · 定义一些管理监控挂钩(接口),用于以后开发针对各种特定问题域的标 准工具。 10 · 提供服务引擎和绑定组件实现的复合型和多样性,不同的供应商可以发布 服务引擎、绑定组件或二者兼具。这些组件之间能够进行可靠性交互,由 这些组件(在 JBI 基础设施之上)构建的系统必须能够集中管理。 3.4 与 其 他 规 范 技 术 的 关 系 (Relationship to other Specifications and Technologies) JBI 实现依赖于 J2SE1.4 或 J2EE1.4。 JBI 使用 Web 服务描述语言([WSDL2.0]和[WSDl1.1])作为服务描述语言,在 WSDL2.0 中,还作为插接式组件交互的基本模型。 交互使用基于 XML 的消息[XML1.0]。XML 的处理遵循当前正在开发的 JAX-RPC2.0 模型[JAX-RPC2.0],因此,JAX-RPC2.0 和 JBI 之间的关系是不正式 的;本规范将来的版本会制定它和 JAX-RPC2.0 之间的正式依赖关系。 JBI 依赖于 Java 管理扩展(Java Management eXtensions JMX)[JMX1.2]。 JBI 企业服务总线(Enterprise Service Bus[ESB])系统中定义了�服务容 器�的概念。 3.5 角色(Roles) 一个功能完善的集成产品须发布一系列满足或超过标准 JBI 系统要求的关键 组件。设计时,JBI 对解决方案的多数必要元素是沉默的。例如,服务引擎应该 被看作一个业务逻辑的容器,业务逻辑使用的词汇范围从有注释的 Java�到 XML (如 XSLT),这些词汇不是 JBI 定义的。JBI 假定在发布一个总体业务解决方案 时,公共的底层对象扮演一些不同的角色。 11 3.5.1 引擎开发者(Engine Developers) 一个符合 JBI 规范的服务引擎(SE)实现需要实现规格化消息路由(Nomalized Message Router[NMR]).另外,SE 开发者须实现组件生命周期和管理接口,并且 必要的话还要实现一个部署接口。如果 SE 作为一个容器,SE 开发者可能要提供 用于简化特定的 SE 产品的工具。 3.5.2 绑定开发者(Binding Developers) 一个符合 JBI 规范的绑定组件(BC)实现的要求同 SE。它们同 SE 主要的不同 点在于,绑定组件使用的远程访问协议和提供的服务不同。 3.5.3 JBI 系统提供者(JBI Environment Providers) JBI 兼容的系统的提供者须支持本规范指定的标准化接口。JBI 系统可选择 使用 J2EE�1.4 或更新的平台,但不是必须的。如果不支持 J2EE,那么必须支持 J2SE1.4 或更新的版本。 JBI1.0 兼容的系统必须支持至少一个 WS-I Basic Profile1.1[http://www.ws-i.org/Profiles/BasicProfile-1.1.html]绑定组 件的实现。 一个符合 JBI 规范的系统可选择发布一个服务引擎的实现,但不是必须的。 3.5.4 J2EE�平台提供者(J2EE�Platform Providers) J2EE�平台提供者可选择发布一个包括服务引擎、绑定组件和应用级工具的 完整 JBI 系统。J2EE�平台提供者当前并不要求必须支持 JBI。 12 3.5.5 JBI 应用开发者(JBIApplication Developers) JBI 应用开发者使用特定的 SE 和 BC 实现定义的词汇和工具,建模、设计、 开发和部署业务组件。这样整个 JBI 系统变得与 JBI 应用程序开发者无关了。 许多这样的开发者开发 XML artifacts 来定义服务引擎和绑定组件。这不是 传统的重点放在代码编写的 J2EE 和 J2SE 领域开发者的工作模式。 13 4 JBI 系统架构(Architecture of the JBI Environment) JBI 提供了一个插接组件放置的环境。该环境为组件服务的运行,组件之间 的交互和整个 JBI 系统及其安装组件的管理提供了一套服务。 JBI 使用标准的服务描述语言来描述插接组件间基于消息的服务调用达到组 件之间的交互。这种方式为组件所提供和消费的服务提供了统一的模型。 JBI 为 JBI 环境(包括已安装的组件)的管理提供了一套服务,包括组件的 安装和组件生命周期管理服务。 4.1 基于 WSDL 的消息模型(WSDL-based Messaging Model) JBI 使用 WSDL1.1 和 2.0 规范描述组件所提供和消费的服务模型。在 WSDL 两个版本中,术语定义存在差异的地方以 WSDL2.0 为准。WSDL 在以下两个层面 上定义了基于消息的服务模型: · 抽象服务模型(Abstract service model):使用抽象消息模型定义的, 未限定到特定消息交换协议的服务 · 具体(限定)模型(Concrete[bound] model):指限定到特定协议和通 信端点的抽象服务。 JBI 使用抽象服务模型作为组件交互的基础。组件在交互过程中扮演以下一 种或两种角色: · 服务提供者(Service Provider):该组件直接提供该服务或作为外部服 务提供者代理。 · 服务消费者(Service Consumer):该组件直接调用该服务或作为远程服 务消费者代理。 WSDL 模型使用名字来标识模型中的各种组件,WSDL 模型使用以下两种类型 的模型: 14 · 限定名(Qualified names):一个 XML 命名空间(URI)和简单名字组成 的名称对,用于全局命名; · 简单(非限定)名(Simple [non-qualified] names):只有简单名字, 没有关联的 XML 命名空间,用于局部命名。 WSDL 组件模型示意图如下所示,该模型将在以下几节详细讨论。 图 3 WSDL 组件模型示意图 4.1.1 抽象服务模型(Abstract Service Model) WSDL 服务描述中抽象服务模型的定义如下: · 抽象消息类型(Abstract Message Type):消息类型定义了合法的消息 结构和约束,一般通过 XML Schema 来表示。消息分为两类:常态消息 (normal)和故障消息(fault),常态消息是指服务正常处理过程中的 消息,故障消息用于描述非正常的处理条件。 · 抽象操作(Abstract Operation):与某种服务进行交互时的一次操作, 该服务由服务消费者和提供者间交换的常态(或故障)消息来定义。抽象 操作定义如下: o 操作名称(Operation Name):定义操作的限定名 o 消息交换模式 MEP(Message Exchange Pattern):消息(包括常 态消息和故障消息)在消费者和提供者之间传递的顺序、方向和基 数(Cardinality) o 消息类型(Message Types):MEP 中的消息的类型 · 抽象服务类型(Abstract Service Type):一组相关联的抽象操作 (Abstract Operation)的集合。在 WSDL2.0 中抽象服务类型用术语�接 口(interface)�表示,在 WSDL1.1 中用术语�端口类型(portType)� 15 表示,本规范中沿用�接口�术语。注意不要同 Java 语言中的接口混淆。 抽象服务类型即接口定义如下: 接口名称(Interface Name):用于标识服务类型的全局限定名,在 JBI 中接口 名称还用来指明服务类型; 扩展的接口(Extended Interface):扩展了其他服务类型的服务类型,类似于 Java 中的接口类型。一个服务类型可由其他几个服务类型组成。 4.1.2 具体服务模型(Concrete Service Model) WSDL 中的具体服务模型建立在抽象服务模型之上,为抽象服务同特定通信协 议及通信端点的映射提供描述信息。为了尽可能的保持通信协议中立,JBI 中组 件间的交互主要基于抽象服务模型,但为了与 WSDL 服务模型一致,组件间的交 互使用 WSDL 具体服务模型来定义。JBI 使用的 WSDL 具体服务模型非常简单,在 大多数情况下可以将其等同为抽象服务模型看待,从而为组件间的交互构建了一 个简单的处理模型。 具体服务模型定义了以下几个概念: · 绑定类型(Binding types):标识服务所绑定的协议类型; · 端点(Endpoints):为服务消费者指明通过特定协议与服务提供者交互 所需的通信端点的信息。在 JBI 中,端点是一种形式上的标识,其内部使 用的协议是基于 Java 的标准 JBI 消息契约,与通常的通信协议无关。JBI 中端点的定义包括以下几个概念: o 端点名称(Endpoint name):用于标识服务中的端点的简单名 o 绑定类型(Binding type):该端点关联的绑定类型 · 服务(Service):提供访问该服务的一组端点的集合,一个服务实现了 特定的服务类型(接口)。一个服务包含如下信息: o 服务名称(Service Name):标识特定服务实现的限定名 o 服务类型名称(Service Type Name):服务实现的接口名。 o 端点(Endpoints):服务�包含�一个或多个端点,通过每个端 点都可以访问该服务 通常,一个端点通过结合其服务名称和端点名称来识别,该结合称之为服务 端点(Service Endpoint)。 16 4.2 规格化消息(Normalized Message) 规格化消息(NM)包含两部分:如上所述的抽象的 XML 消息和消息元数据(即 消息上下文信息)。消息上下文可以为特定的消息提供组件(插接组件和系统组 件)处理该消息时所需的附加信息。消息元数据可以影响其所关联的消息在 JBI 系统中的处理过程。 4.3 JBI 顶层架构(High-Level Architecture) 下图是 JBI 架构的顶层视图。 图 4 JBI 架构顶层视图 整个 JBI 系统存在于单个 JVM 中。JBI 系统外部的节点是外部服务消费者和 服务提供者,代表了 JBI 要集成的外部实体。这些外部实体可以通过各种各样的 技术与 JBI 系统中的绑定组件交互。服务引擎本质上一个容器,用来放置 JBI 系统内部 WSDL 定义的服务提供者和服务消费者。 图 4 展示了 JBI 核心的组件架构,这些组件的集合称作 JBI 系统(JBI Environment)。每个 JBI 系统中都有一组用于提供操作支持的服务,这组服务 中的关键是规格化消息路由(Normalized Message Router[NMR]),它提供用于 消息交换和组件交互的基础设施。此外,JBI 还定义了一个可插拔组件框架,用 于添加服务引擎(SE)和协议绑定组件(BC)。组件框架在图 4 中用黄色 C 形多 边形来表示。 17 图中 JBI 系统右边的部分展示了 JBI 的管理特性。JBI 定义了一套标准的基 于 JMX 的控制允许外部管理工具(图中最右边)执行各种系统管理任务,同时也 管理组件本身。 JBI 核心的消息交换实现了上文所述的 WSDL 消息交换模型。消费者组件生成 服务请求,通过 NMR 路由分发到提供者组件。例如,BPEL 服务引擎可能请求一 个连接到 WS-I 绑定组件的外部服务提供者提供的服务。NMR 把这个请求发送给 WS-I 绑定组件。此时服务引擎就是一个服务消费者,而绑定组件是一个服务提 供者。 JBI 系统提供的所有服务都可以发布为 WSDL 描述的服务(准确的说是�服务 端点�)。服务引擎提供的服务与绑定组件提供的服务(实际上是外部系统提供 的服务)都可以用服务端点描述,从而为服务的提供定义了统一的模型而不用关 心服务的具体位置。 服务消费者可以通过 WSDL 服务名称而不是服务端点地址来识别所需的服务。 这种方式降低了服务消费者和提供者之间的关联,从而允许 NMR 选择合适的服务 提供者。服务消费者也可以通过解析服务端点引用(Endpoint Reference)来识 别服务。例如, JBI 组件可以通过解析消息中的服务端点引用回调其指向的服 务。 除了组件框架和 NMR,JBI 系统的其他部分提供了生命周期管理,环境检查, 管理和配置等基础服务,这使得 JBI 系统成为一个完整而可靠的运行环境。 4.4 规格化消息交换(Normalized Message Exchange) JBI 系统的首要功能是将规格化消息交换(ME)从一个组件路由到另一个组 件。交换的消息使用一种规格化的形式。 绑定组件必须将绑定的消息(特定协议和传输格式的消息)转换成规格化形 式。绑定组件和服务引擎通过传输通道(Delivery Channel[DC])与 NMR 交互, 传输通道为消息的接收和分发提供了双向传输的契约。 18 图 5 外部服务消费者消息处理视图 如图所示,一个外部服务消费者通过特定协议和传输器发送一个服务请求到 绑定组件,绑定组件将请求转换成规格化消息。然后,绑定组件根据 NM 构建消 息交换(Message Exchange[ME] 是 WSDL 消息交换模型中各种简单消息交换模式 中消息的容器),绑定组件设定描述将要执行的服务和操作的元数据信息,最后, 在步骤 2 中,绑定组件将消息交换通过传输通道(DC)发送给 NMR,NMR 将消息 交换分发到服务提供者。 上述过程中,由 NMR 选择合适的服务提供者,然后把消息交换(ME)路由到合 适的服务提供者。服务提供者必须从传输通道中主动接收(pull)消息交换。 相反的操作图 6 所示,只在绑定组件处与图 5 有少许不同。 图 6 外部服务提供者消息处理视图 19 如图所示,一个消费者(SE/BC)创建一个规格化消息 NM 并将其放入一个新 的消息交换(MessageExchange)中.该消息交换的地址被设定为一个服务端点 (ServiceEndpoint),服务引擎未指定用哪一个组件来处理该服务请求。消息 交换的发送和接收同前例所示。绑定组件接收到 ME 后将规格化消息转换为与协 议和传输相关的格式,并将其发送给外部服务提供者。 4.5 管理(Management) JBI 系统(包括绑定组件和服务引擎)通过 JMX 进行管理。本规范定义了若 干管理 Bean(MBean)类型,为 JBI 系统和插接组件提供了一致的管理环境。 管理接口支持的主要功能如下: · 组件(服务引擎和绑定组件)的安装 · 组件的生命周期管理(启动/停止等) · 组件服务描述信息(Service Artifacts)的部署。组件描述信息支持在 内部运行环境中动态添加新的内容。例如,SE 是一个 XSLT 引擎,要安装 到容器中的新 XSLT 样式表就是服务描述信息。 · 监控和管理 4.5.1 组件安装(Component Installation) 服务引擎和绑定组件必须通过管理接口进行安装。本规范中动词�安装 (install)�指提供组件基本功能的二进制文件及相关资源的安装。安装 (install)不同于部署(deployment),部署指根据特定的应用为组件运行添 加相关的描述信息,从而定制组件的行为。例如,一个 XSLT 转换引擎安装后, 可以通过部署特定的转换样式表(.xsl 文件)使转换引擎提供所需的转换服务。 4.5.2 生命周期管理(Life Cycle Management) 引擎或绑定组件一旦安装,就可以使用本规范定义的 MBean 接口启动或停止 该组件。该类控制称为生命周期管理。 20 4.5.3 服务单元部署(Service Unit Deployment) 如上所述,部署是指为安装的引擎或绑定组件提供与组件功能相关的资源。 这些资源称为服务单元(Service Units)。本规范未对服务单元的内容作任何 说明,其对 JBI 来说是不透明的。 服务单元组合成一个聚合的部署文件称为为服务集合(Service Assembly)。 服务集合包含一个部署描述符,用于指明每个服务单元所要部署到的目标组件。 4.6 组件框架(Component Framework) JBI 组件框架为绑定组件及服务引擎提供了一套可插拔的接口用于与 JBI 系 统进行交互。该框架为所有的 JBI 操作服务提供接口。 组件与 JBI 之间的交互有两种机制:SPIs(Service Provider interfaces) 和 APIs(Application Programming interfaces)。SPIs 是绑定组件或服务引 擎实现的接口;APIs 是组件框架向绑定组件和服务引擎发布的接口。组件框架 和组件之间的交互契约在�组件框架�和�格式化消息路由�章节进行详细描 述。该契约定义了 JBI 系统中为达到特定的功能目标,组件框架和 JBI 组件各自 应承担的职责。 4.7 规格化消息路由(Normalized Message Router) 规格化消息交换的传输依赖于规格化消息路由(NMR)在服务消费者和提供 者之间路由。NMR 能够根据消息自身的特性和应用系统的需求支持不同服务品质 (QoS)的消息传输。 根据绑定组件和服务引擎协作的需要,NMR 支持的 QoS 包括: · 最大努力(Best effort):消息可能被丢弃或分发多次 · 最少一次(At least once):消息不可能被丢弃,但存在重复发送 · 仅有一次(Once and only once):消息保证只发送一次 21 详见�规格化消息交换�一章。 4.8 组件(Components) JBI 支持两种组件:服务引擎和绑定组件。这两种组件的模型及 API 定义是 一样的,JBI 只是通过一个标记来区分这两种组件。实际上,JBI 中服务引擎和 绑定组件实现不同的功能。(这种区分同样适用于 JBI 定义的管理接口) 4.8.1 服务引擎(Service Engines) 服务引擎(SE)在 JBI 系统中表现为业务逻辑驱动。引擎可以编排服务的消 费和提供,例如一个长时间的业务处理进程既可以提供服务同时自身也消费服 务。服务引擎可以提供简单的服务,如数据转换;也可以提供复杂的路由或 EDI 服务如消息校勘/反校勘(collation/de-collation)。 服务引擎可以通过聚合其他服务来构造新的服务。WS-BPEL 语言正是使用的 这种重要的合成模式,通过多个服务构造复杂的处理过程。 4.8.2 绑定组件(Binding Components) 绑定组件用于根据特定协议和传输器发送和接收消息。绑定组件把消息在特 定于协议的格式和规格化格式之间进行转换,使 JBI 系统只需处理规格化消息, 从而把 JBI 系统与特定协议分离。(注意,特定于协议的相关信息可以用规格化 消息或消息交换的元数据信息表示,供服务引擎或者绑定组件使用,这些元数据 信息对其他的 JBI 系统组件是不透明的。) 4.9 举例(Examples) 下面的例子演示了如何使用 JBI 系统和组件来完成典型的系统集成任务。 22 4.9.1 单向消息适配(One-way Message Adapter) 在这个场景中,JBI 系统为一条单向消息提供了一个简单的消息适配服务。 一条消息从外部发送到 JBI 系统中,经过转换后发送到外部目的地系统。这是一 个简单的点对点的消息传输模式,用于应用到应用(A2A)的整合,如下图所示: 图 7 单向消息适配器消息序列图 注意,序列图中的双箭头线表明消息通过 NMR 路由传递。这是一个非常重要 的特征:组件之间是松散耦合的。每一个组件只告诉 NMR 其所发送消息的目的地 的服务名称,由 NMR 来决定消息路由到哪一个组件。 Client1 作为一个服务消费者希望向 Service1 提供的服务发送一个单向 (one-way)服务请求。不幸的是 Client1 和 Service1 使用不同的消息格式和消 息传输协议,因此需要采用一个集成中间件来适配两种不同的消息格式和消息传 输协议。这里的中间件即是 JBI 系统,上图表示为中间的大圆角矩形。图中单个 的对象包括: · BC1:使用 Client1 采用的消息协议(可能是遵循 WS-I BP 1.1 的 SOAP 协议)的绑定组件。 · SE1:一个提供轻量级排序服务的服务引擎,可以通过配置对消息进行修 改和推进。 23 · SE2:一个采用 XSLT1.0 转换消息的服务引擎。 · BC2:使用 Service1 采用的消息协议的绑定组件,该例中是 HTTP 之上的 AS2 协议。 消息序列图中的消息交换过程详见以下部分: · Client1 到 BC1。Client1 向 Service1 发送请求,请求的载荷为 REQ1。 Service1 的服务端点为 BC1,Client1 使用自己的消息交换协议与 BC1 交 互。 · BC1 将传入的请求规格化为 NM,然后通过 NMR 路由该消息。本例中 JBI 实例将到 Service1 的请求消息发送到 SE1。 (SE1 是一个提供轻量级排 序和转换服务的引擎) · SE1 选择需要执行的转换类型,向转换服务发送一个请求把 REQ1 转换成 REQ1A。NMR 将 REQ1 发送到转换服务 SE2,SE2 执行转换并同步返回转换 结果(标记为 REQ1A)到 SE1。 · SE1 完成其操作后将消息转换结果 REQ1A 发送到 Service1(NMR 会将该结 果路由给 BC2)。 · BC2 解编规格化消息,将其发送给 Service1(单向)。 24 5 规 格 化 消 息 路 由 (Normalized Message Router) 规格化消息路由(NMR)从 JBI 组件(服务引擎或绑定组件)接收消息交换 并将其路由到适当的组件进行处理。这种中间消息交换处理模型把服务消费者和 提供者分离,并允许 NMR 在消息交换的生存周期中可以执行一些附加的处理。 注意,本章中使用 WSDL2.0 中的术语而不是 WSDL1.1。 5.1 关键概念(Key Concepts) 本节介绍 NMR 架构中的几个关键概念。NMR 的目标是允许组件之间以服务提 供者和服务消费者的身份,使用基于 WSDL 的服务描述彼此交互。这是组件可以 进行混合匹配(mix-and-match)装配、构造集成解决方案和服务基础的关键。 WSDL [WSDL 2.0, WSDL 1.1]为 JBI 组件的交互提供了基本模型和描述机制。 WSDL 提供了一个基于 XML 消息交换操作的抽象服务模型,该模型可以通过扩展 提供特定的绑定信息:将抽象模型映射到实际的通信协议和端点[WSDL 2.0 bindings] 的特定的协议信息。 JBI 扩展应用了 WSDL 的抽象消息模型,可以把 NMR 看作是一个抽象的 WSDL 消息系统基础平台[infrastructure],绑定组件和服务引擎在这个平台上提供和 使用 WSDL 定义的服务。 WSDL 定义了一项服务提供者和消费者之间的消息交换操作,消息交换的参与 者依照各方都能理解的一种消息交换模型进行操作。一组相关联的操作称作�接 口�(WSDL1.1 中称为端口类型)。一个�服务�实现这样的一个�接口�。一 个服务具有一个或多个端点,每个端点通过一种特定的绑定(消息通信协议)为 外部系统访问该服务提供入口。 所有的这些 WSDL 概念都被 JBI 用于在 APIs 和 SPIs 中构建服务模型。 25 5.1.1 服 务 的 消 费 者 和 提 供 者 (Service Consumers and Providers) JBI 引擎和绑定组件可以作为服务消费者,服务提供者或两者兼具。服务提 供者通过端点(endpoint)提供 WSDL 描述的服务;服务消费者发送消息交换调 用特定的操作来使用服务。服务(service)实现了 WSDL 接口,WSDL 接口是通 过交换抽象定义的消息来描述的一组相关的操作。 服务消费者和服务提供者之间通常只共享抽象的服务定义而不是具体的端 点信息,因而两者之间是松耦合的。这种结构把服务的消费者同特定的服务提供 者实现(如特定协议)分离开来。 一个 WSDL 接口可以具有多个服务实现,服务消费者在查找实现了某个接口 的提供者时,可能会查找到多个实现了该接口的服务提供者(服务和相关联的端 点)。 5.1.2 规格化消息(Normalized Message) JBI 使用�规格化(normalized)�消息的概念描述服务消费者和提供者之 间的交互。一条规格化消息由以下三个主要部分组成: · 消息载荷(payload):符合抽象 WSDL 消息类型,不具有任何协议编码或 格式信息的 XML 文档(这不是一个消息的规范格式)。 · 消息属性(或元数据):包含了在消息处理过程中获得的与消息相关的额 外信息。消息属性可以包含消息的安全信息(例如消息接收方的签名信 息),事务上下文信息和组件特定的信息。 · 消息附件:消息载荷(内容)的一部分可以由附件构成,附件由消息载荷 来引用,并且附件中包含一个可以操作附件内容的数据处理器。这些附件 可以是非 XML 格式的。 规格化消息通过抽象 WSDL 消息类型定义为组件间的交互提供了互操作。 26 5.1.3 传输通道(Delivery Channel) 传输通道(DeliveryChannel)是绑定组件和服务引擎与 NMR 之间通信使用 的双向通信管道。传输通道构成了服务消费者,提供者和 NMR 之间的交互契约, 即 API 接口。服务消费者使用传输通道开始服务调用,服务提供者使用传输通道 从 NMR 接收服务调用。既作为服务提供者又作为消费者的组件使用同一个传输通 道完成这两种功能。 以一个绑定组件接收 JBI 系统外部的服务消费者的请求为例,当接收这种传 入的服务调用请求后,该绑定组件通过其传输通道与 NMR 交互时必须扮演服务消 费者的角色(在此用例中,绑定组件可以看作是一个服务消费者的代理)。 每个组件都具有唯一的一个传输通道,因此传输通道的实现必须支持在多线 程环境下的并发使用。 5.1.4 运行时端点激活(Run-time Endpoint Activation) 运行时激活是服务提供者激活其提供的实际的服务的过程。在该过程中,服 务提供者将其提供的服务通知 NMR,这样 NMR 可以将服务调用路由到该服务。端 点激活分为两步: · 向 NMR 声明一个服务端点 · 提供描述该端点定义的元数据信息 向 NMR 声明一个服务端点是绑定组件或服务引擎向 NMR 激活一个端点名称的 过程。在 NMR 中声明的端点名称必须有相应的元数据信息详细描述该端点的注 册,这部分详细信息通过使用 SPI 来提供。 27 5.1.5 服 务 调 用 和 消 息交 换 模 式 (Service Invocation and Message Exchange Patterns) 服务调用指服务消费者和服务提供者之间的一个端对端交互的实例。尽管无 法在 JBI 中定义一套完整的服务调用模式,但是 JBI 实现必须支持以下列表中的 交互模式: · 单向交互(One-Way)模式:服务消费者向提供者发送一个请求,服务提 供者不必向消费者返回任何错误(故障)信息。 · 可靠的单向交互(Reliable One-Way)模式:服务消费者向提供者发送 一个请求。如果服务提供者处理该请求失败,会向消费者返回出错信息。 · 请求-回复(Request-Response)模式:服务消费者向提供者发送一个请 求,并期望服务提供者响应。如果处理请求失败则返回出错信息。 · 请求-选择回复(Request Optional-Response)模式:服务消费者向提 供者发送一个请求,并期望服务提供者响应。消费者和提供者接受到一个 消息后,都可以选择是否应答。 上述提到的消费者和提供者角色可能是绑定组件也可能是服务引擎。当一个 绑定组件作为服务消费者时,说明存在一个外部的服务消费者;同样,当一个绑 定组件作为服务提供者时,说明存在一个外部的服务提供者。当服务引擎作为服 务提供者或消费者时,说明该服务引擎是一个内部参与者。 WSDL 2.0 预定义扩展[WSDL 2.0 Extensions]定义了一个消息交换模式(MEP) 作为�一个操作中的所有抽象消息的顺序和基数�。JBI 使用该模式定义消费者 节点和提供者节点之间的交互。该模式根据消息类型(normal 或 fault)和消息 流向来定义。 MEPs 总是以提供者的角度来理解。例如,在请求-回复交互模式中, MEP 的 定义是 in-out,其消息流从提供者的角度来看,请求(Request)是输入(in), 回复(Response)是输出(out)。从服务消费者的角度看,消息流的方向正好 相反,但是 NMR 在与服务消费者交互过程中使用的 MEP 总是从服务提供者的角度 28 来说的。当处理 WSDL MEPs 时,这是一种惯用的处理方式。In-Out 模式示意图 如图 8 所示: 图 8 In-Out 消息交换模式 如图所示,第一条消息(请求)从消费者发送到提供者,从提供者的角度看 其方向是输入(in)。第二条消息(回复)是从提供者到消费者,即输出(out)。 这些交换是按给定的顺序执行的,从提供者的角度这种交换首先是输入一条消息 (in),跟着是输出(out)一条消息,因此这种交互模式命名为输入输出(in-out) 模式。 5.1.6 消息交换(Message Exchange) 消息交换(ME)作为规格化消息的�容器(container)�。ME 不仅封装了 其实现的消息交换模型中的输入(in)消息和输出(out)消息,它还包含了这 些消息的元数据信息以及正在进行的消息交换的状态信息。消息交换代表了 JBI 本地服务调用的一部分。下表说明了服务调用和消息交换模式之间的关系。 服务调用(Service Invocation) 消息交换模式 MEP (提供者角度) One-Way In-Only Reliable One-Way Robust In-Only Request-Response In-Out Request Optional-Response In Optional-Out 表 2 服务调用与 MEP 的映射 29 图 9 两服务引擎之间的单向服务调用 上图描述了两个本地服务引擎间的单向服务调用,包括了一个消息交换实 例:SE1 作为一个服务消费者,通过创建并初始化一个包含了消息请求的 in-only 消息交换来调用所需要的服务操作。如图中 SE1 和 NMR 之间的对象流所示,SE1 将该消息交换实例发送到 NMR。 NMR 决定由哪一个服务提供者提供所请求的服务操作,并把该消息交换实例 传输给选定的提供者。在图中表示为 NMR 到 SE2 的对象流。 注意,该图示并不意味着调用者必须在交换完成之前阻塞当前线程的执行。 调用方在发送和接收消息交换时,调用者可以是事件驱动的,服务引擎的内部状 态的前进不必占用着线程资源不放。 30 图 10 SE 调用远程 JBI 实例提供的服务:Robust In With Fault 下面描述图 10 所示的处于两个不同的 JBI 环境中的服务引擎之间的可靠的 单向调用。注意,规范中未规定如何�联合(federating)�两个分离的 JBI 实例,该例中两个 JBI 实例之间通过 BC1 和 BC2 提供的通信协议使得两者作为远 程的消费者和提供者而相互可见,并不存在影响两者之间服务调用的特殊关系。 SE1 构建并初始化了一个可靠的单向(robust-in)消息实例,并发送到 NMR (在构建 ME 实例的过程中,NMR 为该实例设定了一个唯一标识�X�)。NMR 选 择合适的服务提供者,并将消息交换以可靠的单向消息模式发送给 BC1。BC1 按 照其所实现的协议需求封装消息请求,并将该请求发送给服务提供者,在本例中, 恰好是另一个通过 BC2 发布了一个服务端点的 JBI 实例 JBI2。 当 JBI2 实例中的 BC2 组件接收到请求以后,该组件构建一个可靠的单向消 息交换实例(�Y�)并发送给 NMR。JBI2 中的 NMR 选择合适的服务提供者并将 消息交换实例(�Y�)发送给该提供者即 SE2。 SE2 接收实例�Y�,处理完请求之后,SE2 可能选择返回一个故障消息说明 发生了一个应用级别的错误。在本例中,SE2 可以使用实例�Y�返回故障消息, 沿着请求流向的反向路径最后通过消息交换实例�X�到达 JBI1 中的 SE1 组件 31 (在此 MEP 中,存在一个�done�响应信息会沿着相同的路径传递,为了清晰起 见未在图中显示)。 图 11 SE 调用远程服务 下面描述图 11 所示的 JBI 服务引擎与 JBI 系统外部的一个远程服务提供者 之间的请求-响应调用。 服务引擎 SE 创建并初始化一个 in-out 模式的消息交换实例并发送到 NMR, 由 NMR 决定哪一个服务提供者应当处理该调用。在本例中,BC 组件被选中,BC 接收到该消息交换(in-out 模式),将其反规格化(denormalize),然后通过 通信协议发送到外部的服务提供者。外部提供者处理消息请求,返回适当的信息 (正常的回复或者是应用处理层级的错误消息)。BC 组件规格化该回复并封装 到消息交换中,然后发送到 NMR,最终返回给消费者 SE。 5.1.7 端点(Endpoints) 端点,在 WSDL2.0 中指代一个可以通过特定协议访问的特定的地址,用于访 问特定的服务。JBI 使用这个概念表示两种不同类型的端点: · 外部端点(External):JBI 系统外的端点: o 外部服务提供者发布的端点。 o 绑定组件发布的端点,用于代理外部服务消费者。 32 · 内部端点(Internal):JBI 系统内部服务提供者发布的端点,可以通过 NMR 的 API 访问。 绑定组件在内部端点和外部端点之间建立映射,例如,绑定组件提供的内部 端点可以映射到外部服务提供者发布的端点。 在 JBI 中,端点可以通过三种不同的方式进行引用: · 隐式引用(Implicitly):JBI 根据服务类型选择服务提供者端点 · 显式引用(Explicitly):服务消费者根据自身的逻辑或配置选择服务提供 者端点 · 动态引用(Dynamically):在消息交换中使用一个端点引用(EPR)来提供� 回调(call back)�地址供服务提供者返回应用会话进行过程中其它相 关的消息交换信息。EPR 在 JBI 中具有两种不同的使用方式: o EPR 构建(EPR creation):一个组件希望在消息中提供回调地址 时,必须能够构建适当的 EPR。 o EPR 解析(EPR resolution):一个接收 EPR 的组件必须能够解析 该 EPR(也就是将其转换成可用的端点)以便于将消息交换发送到 适当的端点(通常是外部服务提供者)。 5.2 消息交换的构成(Element of a Message Exchange) · 模式(Pattern)�每条消息交换都由一个模式描述,该模式描述了组成 一个消息交换的方向(derection),顺序(sequence),基数(cardinality) 和消息名称(normal 或 fault)。 · 起始组件(Initiator)�构建该消息交换的组件。在所有 JBI 定义的消 息交换模式中服务消费者组件担当消息交换的初始组件。 · 服务组件(Servicer)�处理该消息交换的组件。服务提供者担当服务组 件。 · 角色(Role)�当一个组件�拥有�某个消息交换实例时,该组件所扮演 的角色,包括: 33 o 提供者(Provider)�提供该消息交换请求的服务。 o 消费者(Consumer)�向服务提供者请求一个服务。 · 地址(Address)�一个服务引用,端点引用和 NMR 用来路由消息的逻辑 地址的操作名称。 · 消息(Message)�携带一条或多条消息的消息交换 ME。 · 故障(Fault)�携带至多一条故障信息的消息交换,故障(fault)是一 种特殊的消息。 · 状态(Status)�描述消息交换的状态:error,done 或 active 中的一 种。 · 错误(Error)�用于描述错误状态特征/原因的 Java Exception 对象。 · 属性集(Properties)�消息交换的起始组件和服务组件可以为一个消息 交换关联任意的属性信息。NMR 可以保留某些属性名称用于声明 QoS,安 全,事务或其他操作元数据。 消息交换的生命周期很短,不能够在系统停止或崩溃时保留。由消费者和提 供者组件提供的错误恢复逻辑必须能够处理这类错误案例。能够使 JBI 支持可恢 复性的可靠的消息交换将在 JBI2.0 中进行考虑。 5.2.1 交换概要(Exchange Summary) 下表是 JBI 使用的 WSDL2.0 中定义的消息交换模式。每种定义包含一个故障 处理规则,指定创建消息交换中的哪一种消息来把故障信息从一个参与者传到另 一个参与者。与 WSDL1.1 等同的操作在下表中给出: 消息交换模式名称 消息序列 故障处理规则 WSDL 1.1 操作 In-Only in none One-way Robust In-Only in on in - In-Out in, out replaces out Request-response In Optional-Out in, out on in or out - 表 3 JBI 标准消息交换模式(来自 WSDL 2.0) 34 5.3 规格化消息(Normalized Message) 规格化消息是 JBI 消息交换中的消息。本节定义了规格化消息,同时讨论了 JBI 中处理该类消息的模型。 5.3.1 规格化定义(Normalization Defined) 消息的规格化指的是将协议与业务上下文信息以可传输的方式存储起来的 过程。NMR 处理的所有消息都是规格化的,规格化是一个双向的过程: · 消息的规格化(Normalizing)是将包含了特定上下文数据的消息转换成上 下文中立的抽象表示,本质上说就是将由 NMR 解释的上下文数据转换成一 种 NMR 能够理解的�通用�的表现形式。任何其他的信息(如消息载荷, 附加上下文等)都可以由消息承载并由 NMR 传递,但是,这些信息对 NMR 来说是不透明的。注意,规格化(normalization)并不意味着要将消息载 荷数据规范化(canonicalization)。 · 反规格化消息(Denormalizing)指的是从 NMR 接收消息并将其转换为与上 下文相关的表现形式。反规格化是规格化的逆向操作,例如,一个 SOAP 绑定组件反规格化消息时会将消息适当的部分以及消息元数据放入 SOAP 信封,转化成需要的编码格式。 5.3.2 规格化消息的结构(Structure of a Normalized Message) 规格化消息包含两个不同的部分:上下文和载荷。 · 消息上下文(Message context)指的是一组消息属性集,可为消息关联一 些元数据信息。 · 消息载荷(Message content)实际上是包含了所有消息载荷的原始数据信 息的抽象。此处,术语�包含(contain)�是指包含在描述消息的抽象 数据模型中。 35 5.3.3 处理方法(Processing Methods) 规格化消息抽象并未规定消息载荷的处理方式。消费者可以根据特定上下文 需求自由选择消息载荷的处理方式。例如,一个高性能的绑定组件会考虑使用� 拉(pull)�模式的解析器或原始字节流来序列化消息载荷;另一方面,一个转 换引擎可能需要将整个消息载荷加载到内存中表示成 XML 的 DOM 树以便于查询。 5.3.4 二进制数据(Binary Inclusion) 规格化消息的消息载荷一定是 XML,对于非 XML(包括二进制数据)的数据 通过使用 JAF(Java Activation Framework)将这些数据作为规格化数据的附 件。 5.3.5 WSDL1.1 的支持(Support for WSDL 1.1) 服务提供者可能使用 WSDL1.1 描述其自身而不是用 WSDL2.0。由于 WSDL1.1 的消息模型与 2.0 有很大的区别,JBI 定义了一个映射关系用于将 WSDL1.1 消息 映射成为单个 XML 文档的规格化消息形式。 5.4 NMR 设计(NMR Design) 本节给出规格化路由的详细设计信息。详细讲解 JBI 容器(绑定组件或服务 引擎)和 NMR 之间的契约。 5.4.1 激活(Activation) 如前所述,激活是服务提供者向 NMR 声明其所提供的服务的过程。每个声明 都必须伴有一个描述此声明的相关元数据定义。(这些元数据由组件提供的 SPI 提供)JBI 要求这种声明是用 WSDL1.1 或 WSDL2.0。NMR 假设(并不强制)所有 的这种声明都符合 WSDL 规范。然而,如果元数据格式难看,服务的消费者就很 有可能无法正确的调用该服务。 36 5.4.1.1服务提供者激活(Service Provider Activation) 下图是服务提供者激活的一个领域模型。 图 12 服务激活领域模型 每个提供者激活的端点必须使用元数据描述该服务、端点及其绑定细节。(服 务引擎对其提供的服务的激活使用一种特定的 JBI 定义的绑定类型。) 下面用一个逻辑顺序图描述了激活的情景。 37 图 13 BC 端点激活消息序列图 此图只显示与激活相关的活动,没有表明端点激活和消息交换之间的联系。 1. 作为预处理,BC 提供组件 SPI 的一个实现,组件 SPI 的一部分用于提供 元数据描述的激活端点。(所有的组件都必须提供这个。) 2. BC 激活一个端点的名称。 3. NMR 初始化服务端点。 4. SE 通过端点名称(或其他标准)查询 NMR 以获取端点。 5. SE 使用端点查询 NMR 获得服务端点的元数据描述。 6. NMR 调用 BC 的组件 SPI 获取合适的元数据。 7. SE 解析 NMR 返回的 DOM 文件。 5.4.2 交换消息(Exchanging Messages) 本节对 JBI 支持的四种标准 MEP 进行深入的探讨。值得注意的是 NMR 提供了 一个可扩展的消息交流模型。JBI 供应商可以自由地扩展四种 MEP 的标准目录。 38 每种模式以一个状态交换结束,用于确定交换已经结束。这种方式对于可选 消息(或默认)作为消息交换模式的一部分来说尤其有用,在所有的 MEP 中支持 可靠消息交换。 在标准 JBI 模式中,以起始组件开始的交换模式一般是服务的消费者,它创 建并初始化一个新的交换实例。服务消费者 �拥有�这个消息交换实例直到把 它发送出去(使用 DeliveryChannel.send())。随后这些参与者交替接收和发送 消息交换实例,直到某个参与者把消息交换状态设置为终结状态并把它发送给另 一个参与者。当一个组件接收一个消息交换实例(使用 DeliveryChannel.accept())时,就说它�拥有�一个消息交换。 下图显示了对于每种标准 JBI 消息交换模式,服务消费者和提供者之间可能 的交互。每种模式都是两个参与者(无论它们的角色是服务提供者还是消费者) 之间的契约。注意,当接收一个消息交换实例时,一个参与者可以通过使用 MessageExchange.getRole()很容易地决定它的角色是服务提供者或是消费者。 这有助于参与者在参与较复杂的模式时与参与较简单模式时一样方便。 5.4.2.1图例(Diagram Key) 此处的 MEP 图展示了接下来的图例要使用到的符号。这些图代表了消息交换 的时间顺序,时间在图中显示为从上到下。交替过程(故障或正常回复)使用选 择符号表示。 图 14 MEP 图例 39 5.4.2.2In-Only 消息交换模式(In-Only Message Exchange) 这种模式被用作单向消息交换。 图 15 In-Only MEP 注意: · 服务消费者使用消息发起请求。 · 服务提供者回复状态以完成交换。 5.4.2.3健壮的 In-Only 消息交换模式(Robust In-Only Message Exchange) 这种模式被用作可靠的单向消息交换。 图 16 Robust In-Only MEP 40 注意: · 服务消费者使用消息发起请求。 · 服务提供者可能回复状态或故障。 · 如果服务提供者回复状态,那么交换完成。 · 如果服务提供者回复故障,消费者回复状态以完成交换。 5.4.2.4In-Out 消息交换模式(In-Out Message Exchange) 这种模式被用作双向消息交换。 图 17 In-Out MEP 注意: · 服务消费者使用消息发起请求。 · 服务提供者回复消息或故障。 · 消费者回复状态。 41 5.4.2.5In Optional-Out 消息交换模式(In Optional-Out Message Exchange) 这种模式被用作服务提供者的回复可选的双向消息交换。 图 18 In Optional-Out MEP 注意: · 服务消费者使用消息发起一个请求。 · 服务提供者可能回复消息、故障或状态。 · 如果服务提供者回复状态,那么交换完成。 · 如果服务提供者回复故障,消费者必须回复状态。 · 如果服务提供者回复消息,消费者可能回复故障或状态。 · 如果服务消费者回复故障,提供者必须回复状态以完成交换。 42 5.4.3 消息交换路由(Routing Message Exchange) 服务消费者使用消息交换工厂(MessageExchangeFactory)创建一个新的消 息交换实例,并使用以下提供者可能需要的信息(这些信息为了增加特定性)初 始化这个实例:接口名称、服务名称、端点名称。下面给出了每种地址类型的详 细信息。如果消息交换实例中有多种地址类型,实现时必须使用最特定化的那个 地址类型而忽略其他。 · 接口名称。如果在一个消息交换中指定了接口名称,实现必须使用隐式端 点选择。 · 服务名称。实现必须选择一个属于给定服务名称的服务提供者端点,使用 隐式端点选择。 · 端点。实现必须使用给定的端点作为服务提供者,可以使用直接或间接(直 接路由和间接路由详见 5.4.3.3 节) 如果消息交换指定的服务可以通过不止一个端点来实现(当使用接口名称或 服务名称来查询交换时是有可能的),必须只能选择一个服务提供者端点。这里 不再讨论如何选择端点。 当服务提供者发出一个交换消息之后,总是先将它发送到触发交换过程的组 件。而随后从服务的消费者返回给提供者的交换消息会被发送到一个在交换过程 的初始化阶段就已经确定了的服务提供者端点。 当一个消息交换被发送到一个指定的服务提供者端点,实现必须把消息交换 传输到激活给定端点的组件的传输通道(DeliveryChannel)。 当一个消息交换被返回给一个服务消费者组件,实现必须把消息交换传输到 消费者组件的传输通道(DeliveryChannel)。 43 5.4.3.1实现消息交换地址属性的改变(Implementation Changes to Message Exchange Address Properties) 一个服务消费者可能在初始化消息交换实例的过程中选择性地设置一些消 息交换提供者的地址属性。当一个提供者的地址属性被设置之后,实现禁止改变 其他任何属性(接口名称、服务名称和服务端点)。 当组件发送一个新的交换实例,实现必须把交换实例的端点属性设置为 NMR 选择那个的端点(如果组件没有指定该端点),这个端点作为服务提供者。 注 意,如果组件直接指定了端点,实现禁止改变这个端点值,即使这个端点引用了 一个服务连接。(详见 5.4.3.3 节) 5.4.3.2隐式端点选择过程(Implicit Endpoint Selection Process) 当服务消费者使用任何形式的地址(而不是一个服务端点)指定了所需的服 务提供者,JBI 实现必须隐式地选择服务提供者端点。本节给出实现进行隐式端 点选择的过程中所必须遵守的几点。当服务消费者调用 DeliveryChannel.send 或 DeliveryChannel.sendSync 发送一个消息交换实例时,必须进行隐式端点选 择。 如果在选择的过程中没有候选的服务提供者端点匹配给定的服务地址,或者 没有合适的候选服务提供者,send 或者 sendSync 方法必须抛出一个 MessagingException 异常并给出相应的出错信息详细描述路由故障。 JBI 实现过程中的每个候选服务提供者端点都必须做到如下几点: · 调用服务消费者的 Component.isExchangeWithProviderOkay()方法,提 供属于这个选择过程的消息交换和候选选端点作为该方法的参数 · 调用服务提供者的 Component.isExchangeWithConsumerOkay()方法,提 供属于这个选择过程的消息交换和候选选端点作为该方法的参数。 44 一个可以使得上述两个调用返回为�真�的候选服务提供者端点被认为是 匹配的、适用的隐式选择服务提供者端点。实现必须使用指定的方式选择一个提 供者端点,作为从所有匹配的提供者端点中选择的结果。一个实现选择其找到的 第一个匹配的服务提供者端点可能会导致整个选择过程�短路�。 5.4.3.3消息交换路由和服务连接(Message Exchange Routing and Service Connections) 服务集合可能包含提供部署信息的路由信息,称为服务连接和服务链接类 型。服务连接提供从消费者给出的地址到实际提供者服务端点之间的显式映射。 服务链接类型提供服务消费者组件希望获得的附加信息,JBI 实现使用服务连接 路由消息交换。 服务链接逻辑上被定义为包含以下属性的结构: · 消费者地址。服务消费者提供的地址。有两种形式: o 服务类型名称。消费者使用接口名称指定希望获得的服务类型。 o 服务端点名称。消费者使用限定名(服务 QName 和端点名称)指定 希望获得的服务端点。 · 提供者端点地址。实际的服务提供者的地址,将交换发送给消费者,可以 是一个内部端点或者解析过的端点引用(EPR)。 当一个消费者使用一项特定的服务时,可能在服务单元元数据中声明它 对服务连接如何被提供的期望。此处用术语�提供者链接�来表示。共有三 种可能的提供者链接类型,当且仅当消费者的地址是一个服务端点名称的时 候才提供: · 标准链接。NMR 执行正常路由,包括使用服务连接。 · 硬链接。消费者一般直接指定提供者的端点,路由不受服务连接的影响。 换句话说,消费者要求给定的端点地址必须是一个内部端点。 45 · 软链接。消费者使用一个间接地址指定提供者端点。此时消费者提供一 个�假�(并不存在的)端点。这种类型的链接是消费者的一个声明:给 定的地址必须使用一个服务连接来解析。如果该端点是一个内部端点的话 就会引发错误。 服务单元在它们的部署描述符中声明链接类型。JBI 实现必须标记消息交 换,当组件发送新的消息交换实例到传输通道时服务调用的链接类型是可用 的。 如果一个新的消息交换指定了一个端点,当调用 DeliveryChannel.send 时,JBI 实现必须进行以下几步: · 如果端点指定了一个内部端点且链接类型是�标准链接�或�硬链接�, 发送交换实例至给定的端点。 · 否则,如果端点指定了一个服务连接的消费者端点且链接类型是�标准链 接�或�软链接�,发送交换实例至服务连接指定的提供者端点。 · 再则,抛出一个 MessagingException 异常,在消息中指示错误类型: o 软链接时指定内部端点地址。 o 硬链接时指定服务连接地址。 注意,实现只能使用和当前运行的服务集合相关联的服务连接。 当使用隐式端点选择时,实现必须应用服务连接选择端点。(例如,指 定一个服务类型或服务名称而不是一个端点)。 5.4.4 使 用 动 态 端 点 引 用 (Use of Dynamic Endpoint References) 动态端点引用(EPR)在 5.1.7 节给出定义。最终由绑定组件负责解析接 收到的 EPR,因为 EPR 包含了特定的绑定信息。由于同样的原因,创建 EPR 也是绑定组件的职责。 46 EPR 使用专门的 XML 词汇,这些词汇也是特定的绑定信息所使用的。解析 收到的 EPR 或创建一个新的 EPR(服务引擎)的组件不需要�理解�EPR 词汇, 但并不是禁止这样做。在服务引擎内部创建特定的 EPR 处理操作一般说来是 不明智的举动,因为它在引擎和某种特定的协议之间引进了紧耦合,降低了 系统的可配置性。 EPR 可以为内部端点创建。有两种类型的内部端点,它们由 JBI 实现进行 不同的处理: · 服务引擎提供的端点。这种端点的 EPR 必须使用 JBI 定义的 EPR 词汇来提 供引用。(见 5.5.4.1)。 · 绑定组件提供的内部端点。这种端点的 EPR 应尽可能地引用外部提供者端 点,否则使用 JBI 定义的 EPR 词汇。 EPR 可以为外部端点创建。如上所述,一个内部(绑定)端点作为一个外 部服务的代理,如果可能的话应该直接引用外部提供者的端点。 对绑定组件发布的外部端点(为外部消费者使用),组件需要为这些外 部端点创建 EPR 引用。这些外部端点可以被其他组件通过特定的查询方式发 现。由于这个原因,绑定组件创建并注册这些外部端点。 5.4.4.1绑定组件实现的端点(Binding-implemented Endpoints) 绑定组件需要提供对 ServiceEndpoint 接口的实现,两种 EPR 的情况: · 外部端点。绑定组件为它创建的外部端点(由外部服务消费者访问)注册。 这个外部端点作为一个代理允许外部消费者使用一个内部服务。绑定组件 为外部端点提供的 ServiceEndpoint 实现必须做到以下几点: o getInterfaces()返回由端点的接口限定名(QName)组成的一个数 组。 o getServiceName()返回内部提供者的服务名。 47 o getEndpointName()返回一个合法的端点名称,该名称必须与内部 提供者的端点名称不同。 o getAsReference()返回一个端点引用,外部服务消费者可通过该引 用发送请求至绑定组件。 外部端点注册的唯一目的是提供到这些端点的引用。外部端点本身不能 用来处理消息交换实例。如果组件使用外部端点处理一个消息交换实例, DeliveryChannael.send 方法将抛出一个异常。 · 内部端点。绑定组件解析一个端点引用。组件创建的端点将解析 EPR 所指 向的服务端点。这种类型的端点可以用来处理一个消息交换实例。绑定组 件的 ServiceEndpoint 实现必须做到以下几点: o getServiceName()和 getEndpointName()返回一个合适的、充分限 定的服务名称,这个名称在 EPR 引用的外部端点中是独一无二的。 这里�合适�表明满足以下任一点: § 服务名称作为解析过的 EPR 的一部分。 § 服务名称在绑定组件中是独一无二的。 o getAsReference()返回空。如果端点需要一个 EPR,使用原始 的 EPR。 JBI 实现必须保证,通过解析 EPR 而创建的内部端点处理过的消息交换, 被传输到创建那个内部端点的组件。组件实现必须区分 JBI 提供的 ServiceEndpoint 和组件自己创建的 ServiceEndpoint。一个端点实现的例子 如下所示: 48 5.5 NMR API(NMR API) NMR 为服务引擎和绑定组件提供一个标准的 API。 5.5.1 消息 API(Message API) 消息 API 定义了 JBI 系统中规格化消息的内容和行为。该 API 的主要功 能包括: · 使用一个标准数据模型(XML)存储/检索内容 · 在每个消息的基础上 set/get 上下文信息(属性) 49 图 19 消息 API 类图 5.5.1.1规格化消息(Normalized Message) 一个规格化的消息由以下几部分组成: 50 · XML�有效载荷�文件,在抽象消息定义中定义。即规格化消息的内容。 · 消息属性(元数据),与消息本身相关联。一些属性是 JBI 定义的,另一 些属性可以是组件定义的。 · 消息的二进制附件。 5.5.1.1.1规格化消息内容(Normalized Message Content) 规格化的消息内容(有效载荷)是一个 XML 文件,在服务描述中定义(一 般用 XML Schema1.0)。为了提供处理 XML 的灵活度,规格化消息使用 JAX-P API 中的 TraX Sourcej 接口。在图 19 中描述,在包 javax.xml.transform 中。 规格化消息内容必须和抽象消息定义模型相一致,这个模型在服务提供 者提供的服务描述中给定。 规格化消息的生产者必须使用 NormalizedMessage.setContent()方法设 置有效载荷文件的内容(XML 资源)。规格化消息的消费者应使用 NormalizedMessage.getContent()方法,消费有效载荷文件的内容。 5.5.1.1.2规格化消息附件(Normalized Message Attachments) 消息的附件用一个 Java 活动框架数据处理器(Java Activation Framework DataHandler)表示。NormalizedMessage 接口包含和消息相关的 增加、删除和列表方法。一个消息可能包含任意个附件。 带有附件的规格化消息的生产者负责把一个本地消息的内容映射为带附 件的规格化消息。规格化消息的消费者负责解析消息的 XML 内容并处理相关 的附件。生产者和消费者依赖消息的 WSDL 定义确定规格化消息内容的封装结 构。 WS-I 附件概述 1.0(WS-I Attachments Profile1.0(AP)) [WS-I AP]和 XML 优化包(XML-binary Optimized Packaging(XOP))[W3C XOP]是本领域的 51 两个 Web 服务标准。下一小节给出在规格化消息内容的 XML 体中使用这些标 准引用附件的处理规则。 5.5.1.1.2.1WS-I Attachments Profile1.0 的处理规则(Processing Rules for WS-I Attachments Profile 1.0) · 在消息内容的 XML 体中,每个附件都必须被一个 swaRef 元素/属性引用。 · 在swaRef元素/属性中指定的cid必须与封装在附件内容中的数据处理器 的 id 相匹配。 使用带附件的 SOAP 详见[WS-I AP] 5.5.1.1.2.2W3C XML-binary Optimized Packaging (XOP) 的 处 理 规 则 (Processing Rules for W3C XML-binary Optimized Pachaging) · 每个附件必须被一个 XOP 引用:包括消息内容中的 XML 体元素。 · Href 属性值在一个 XOP 中指定:包括元素必须与封装在附件内容中的数 据管理器 id 相匹配。 使用 XOP 详见[W3C XOP]。 5.5.1.1.3规格化消息属性(Normalized Message Properties) 下表总结了规范定义的规格化消息的标准属性: 名称 类型/值 描述 javax.jbi.security.subject javax.security.auth.Subject JAAS 安全主题,负责消息 的数字签名。 javax.jbi.messaging.protocol.type java.lang.String 创建消息的绑定组件的协 议类型名(使用 WSDL2.0 绑定类型属性值) javax.jbi.messaging.protocol.headers java.util.Map 名称/值,指定绑定组件使 用的协议。名称必须为 52 String 型;值为绑定组件 定义的类型。(对 SOAP headers,值为 org.w3c.dom.DocumentFr agment 节点)。 表 4 标准规格化消息属性 注意,javax.jbi.messaging.protocol.type 和 javax.jbi.messaging.protocol.headers 的属性是由绑定组件设置的。这些属 性值一般只有绑定组件自己使用,因为它们包含特定的绑定信息。其他组件可能 使用这些属性,不过这是不明智的举动,因为它将导致组件和某种特定的协议绑 定。 5.5.1.1.4WSDL 1.1 定 义 内 容 的 消 息 (WSDL1.1-Defined Content Messages) WSDL1.1 使用术语消息部件定义抽象消息,消息部件用模型语言描述(一般 用 XML Schema)。这与 WSDL2.0 和 JBI 使用的规格化消息模型截然不同。为了 允许提供用WSDL1.1定义服务的组件可以同消费者交互操作,JBI为封装WSDL1.1 消息部件定义了一种 XML 文件格式。消费者和提供者可以通过把消息映射为一 种�wrapped doc-literal�的形式从而进行交互。 一个封装的文字化的文件须符合下面所示的模型。 53 这个封套须在 portType(抽象)操作中使用(wsdl:input,wsdl:output,或 wsdl:fault)。文件中的元素是这种消息所有部件的封套。它具 有以下几个属性和元素: · version 属性,必须是 1.0。 · type 属性,包含在封套中的 WSDL1.1 消息定义的限定名。与 wsdl:input,wsdl:output,或 wsdl:fault 消息属性值相关。 · name 属性,与规格化消息的 wsdl:input,wsdl:output,或 wsdl:fault 可 选名称属性相关。如果这个属性没有提供,将应用 WSDL1.1 默认的命名规 则。 · 零或多个元素,表示 WSDL1.1 描述的消息的逻辑部件。消息的 所有逻辑部件必须在此处显示,与在 WSDL1.1 消息描述中定义的顺序一 致。 每个元素必须包含 WSDL1.1 定义的消息的逻辑部分的值。 元素可能包含 XML 元素或非 XML 文本。 转换成封装的文字形式,WSDL1.1 定义的消息的规格化的消息内容也必须符 合基于 WSDL2.0 的规格化消息内容的要求。(例如被表示为一个 javax.xml.Source)。 5.5.1.1.5消息属性(Message Properties) 消息属性是与消息内容相关的元数据。以下是本规范定义的属性及可能用到 的组件: · 安全主题。该属性表明 JAAS 主题的身份,或者为一个消息签名,或者为 一个主题签名,由处理的上下文决定。getSecuritySubject()和 setSecuritySubject()用来读写该规格化消息的属性。 · 名称/值属性对。一个可扩展的属性集,组件可以为使用其它组件或其自 身设置属性。getProperty()和 setProperty()用来读写属性设置; getPropertyNames()可被用来发现所有定义的属性名称。 54 5.5.1.1.6消息附件(Message Attachments) 消息的附件可表示为一个具名实体集,由 Java 活动框架处理器(Java Activation Framework handlers)处理。以下操作可被组件执行: · 使用唯一的名称给规格化消息添加附件。 · 使用唯一的名称给规格化消息移除附件。 · 列表显示规格化消息的所有附件的名称。 · 使用唯一的名称从规格化消息处获得一个附件。 附件内容必须表示为 javax.activation.DataHandler 对象。 5.5.2 服务 API(Service API) 此 API 允许 JBI 组件与 NMR 交互。 55 图 20 NMR API 类图 5.5.2.1传输通道(DeliveryChannel) JBI 组件和 NMR 通过 DeliveryChannel 接口进行交互。传输通道使得组件可 以: 56 · 接收和发送消息 · 创建消息交换工厂。 5.5.2.1.1消息交换工厂 API(Message Exchange Factory API) 所有的消息交换实例使用消息交换工厂的实例来创建。使用组件的传输通 道,通过以下三种方式之一可以创建消息交换工厂: · createMessageExchangeFactory(ServiceEndpoint)创建一个工厂,设置 所有创建的交换实例的 endpoint 属性为给定的端点。当处理显式选择的 端点或动态解析的端点时是很有用的。 · createMessageExchangeFactory(QName interfaceName)创建一个工厂, 设置所有创建的交换实例的 interfaceName 属性为给定的接口名称。 · createMessageExchangeFactory()创建一个工厂,设置消息交换的所有属 性都为默认值(null 或空)。 · createMessageExchangeFactoryForService(QName serviceName)创建一 个工厂,设置工厂创建的所有交换实例的 service 属性为给定的服务名 称。 5.5.2.1.2创建消息交换(Creating Message Exchanges) MessageExchangeFactory 提供三种不同的方法创建新的消息交换实例,支 持三种不同的需要: · createExchange(serviceName,operationName)根据服务名称和操作名称 创建。允许组件快速装配一个消息交换实例,不用检查服务元数据中的 MEP。 · createExchange(URI)根据 MEP URI 创建。允许支持 MEP 的扩展。 · createInOnlyExchange()等。使用指定 MEP 的方法创建。在编码阶段确定 了 MEP 需求时,使用此方法便于创建标准消息交换。 57 5.5.2.1.3发送消息交换(Sending Message Exchanges) DeliveryChannel 提供两种基本方式发送消息交换: · Send(exchange).异步消息传输:此方法不会阻塞。ME 的传输可同调用 send()的线程并发执行。 · SendSync(exchange).同步消息传输:此方法必须阻塞当前执行的线程直 到 ME 返回。 后者用一个变量存放超时参数。JBI 组件可以使用简单同步消息交换而不用 在消息交换没有按预期返回时管理�粘滞�线程。为支持超时特点,sendSync() 方法返回一个布尔值来表示消息交换实例是否成功返回。如果第一个超时, sendSync(exchange)一般返回真。如果第二个超时,sendSync(exchange,long) 返回假,消息交换被设置为 ExchangeStatus.ERROR 状态。如果一个提供者组件 试图发送一个这样一个消息交换(例如一个因 sendSync()超时而失败的消息交 换),实现必须停止调用 send()并抛出一个相关的 MessagingException 异常。 当一个消息交换实例使用一种 sendSync 方法发送时,JBI 实现设置消息交 换实例的以下属性: Javax.jbi.messaging.sendSync. 这个属性可被请求的 servicer 使用,表明这种消息交换应受到不同的对待。 注意,在异步消息交换的情况下,无法保证被接收的消息交换 (通过接收者 调用 accept(),下节讨论)就是最初发送的同一个对象。事实上,唯一的保证是 消息交换的 ID 必须是相同的。 5.5.2.1.4接收消息交换(Rreceiving Message Exchanges) DeliveryChannel 提供两种方式接收消息交换: · accept().此方法在从 NMR 接收到一个消息交换实例之前是阻塞的。 58 · accept(timeoutMS).此方法作用类似 accept(),当超过给定的时间之后, 方法返回 null,表明没有接收到任何消息。 消息接收一般符合�拉�模型:JBI 组件用自己的执行线程从传输通道把 消息交换实例�拉�出来。组件可能会使用不止一个这样的线程做到并发消 息接收。JBI 实现可满足一个组件以任意的顺序发出的多个 accept()请求。 5.5.2.1.5关闭传输通道(Closing Down a DeliveryChannel) 组件可通过调用一个 DeliveryChannel 解活(deactive)所有的服务端点: · close().此方法关闭所有组件激活的活动端点。 · deactivateEndpoint().调用此方法作用同上。 一旦传输通道这样关闭就不能再次开放了。相反,要想使组件继续和 NMR 交互,需要创建一个新的传输通道实例。 当一个传输通道关闭之后,该通道创建的所有消息交换工厂实例都不能正常 工作;所有试图使用这样的工厂创建消息交换实例都将导致抛出一个消息异常, 表明相关的传输通道已经关闭。 5.5.2.2服务描述 SPI(Service Description SPI) 使用组件接口,组件使用 getServiceDescription(ServiceEndpoint)方法 提供服务相关的元数据。方法返回一个 DOM 文件,给出某个端点提供的服务的 WSDL 描述。如果端点不是激活的或者端点不是由该组件提供的, getServiceDescription(ServiceEndpoint)方法返回 null。 该 DOM 文件可以是 WSDL2.0 兼容的或者 WSDL1.1 兼容的,有以下附加属性: · 文件不能使用元素。(文件必须是单独 的)。 59 · 服务引擎提供的端点必须使用在�JBI 服务引擎 WSDL 绑定�一节定义的 绑定类型。 文件必须提供指定服务的完整定义和端点名称,包括服务接口和操作。(当 然也包括使用的消息交换模式)。 5.5.2.3消息交换模式 APIs(Message Exchange Pattern APIs) 下图显示了所有内嵌的 MEP 的消息交换模式 API: 图 21 MEPAPI 类图 所有的消息交换实例都必须由消息交换工厂(MessageExchangeFactory)的 实例提供的工厂来创建。 60 消息交换实例的拥有者可以是起始组件、服务或 NMR。创建或接收一个消息 交换实例就等于把所有权授给创建(或接收)的那个组件。一旦对某个消息交换 实例调用 send()方法,组件就立即交出了它对这个消息交换实例的所有权。 sendSync()在调用该方法的过程中交出其对消息交换实例的所有权。当调用 过程结束(返回真),组件恢复对该消息实例的拥有权。 对一个消息交换实例的拥有权意味着拥有者可以读写这个消息交换实例。如 果一个组件(或 NMR)对一个消息交换实例不具备拥有权,就不能读写这个实例, 但是可以读取消息交换的状态,因为状态的访问可以不必考虑拥有权问题。如果 一个组件不是当前消息交换实例的拥有者,而试图对该实例调用任何方法(除了 getStatus()),就会抛出一个相应的 java.lang.IllegalStateException 异常。 5.5.2.3.1消息交换(MessageExchange) 父接口 MessageExchange,提供一般方法给实现某个特定消息交换模式的 API。MessageExchange 实例为一串规格化消息交换和状态交换提供上下文环境, 可被看作一个带状态的规格化消息的容器。 每个消息交换实例都可以通过 MessageExchange API 访问以下特征: · 状态。ExchangeStatus 在一个消息交换实例生命周期中提供其状态的可 能值。(安全类型枚举(type-safe enumeration))。一个新消息交换实 例在其生命周期内是激活的,直到状态转变为 DONE 或 ERROR。可分别通 过 getStatus()和 setStatus()来获得和设置该状态。 · 出错状态源。实例可保留一个处理错误的根源(Java 异常)。见 getError() 和 setError()。 · 交换 ID。每个 MessageExchange 实例必须拥有一个 JBI 实现赋予的唯一 的标识字符串。JBI 组件可以用这个标识把异步的响应和初始的请求关联 起来。 · 交换模式。每个 MessageExchange 实例拥有一个交换模式标识。标准消息 交换模式由 WSDL2.0 赋值的 URI 来标识。 61 · 交换角色。当一个组件创建或接收某个消息交换实例,它必须认识到自己 在交换中的角色。在简单交换模式中可以使用交换的状态、消息和故障等 特点很容易地确定组件的角色。在复杂的交换模式下,组件使用 getRole() 方法可以更容易地确定其在交换中的角色。 · 服务名称。交换调用的服务的限定名。 · 操作名称。交换调用的操作的限定名。 · 服务端点名称。服务提供者端点可选的限定名。(服务名称加端点名称)。 · 规格化消息。交换实例相关的规格化消息的工厂。提供一些方法来创建、 设置和查询这些消息。见 createMessage(),setMessage()和 getMessage()。 · 故障信息。交换实例相关的故障消息的工厂。提供一些方法来创建、设置 和查询这些消息。见 createFault(),setFault()和 getFault()。 · 事务上下文。如果事务的上下文非空(non-null),执行该交换。见 getProperty()和 setProperty()。事务由常量 MessageExchange.JTA_TRANSACTION_PROPERTY_NAME 来命名。 · 属性。一些非 JBI 的消息交换特点可以作为属性存储:名称-值对,值(对 JBI 来说)是一个不透明的 java.lang.Object。 MessageExchange API 提供足够的功能支持所有标准 MEP。然而,在 API 层 次上并不区分�in�和�out�消息,使得理解 Java 编码层的消息交换变得困 难。为解决这个问题,提供了一套特定的 MEP API,在以下四节给出详细介绍。 5.5.2.3.2InOnly 消息交换(InOnly Message Exchange) 这个子接口为�http://www.w3.org/2004/08/wsdl/in-only�MEP 提供 API。 提供以下特定的 MEP 方法: · setInMessage(msg).只能调用一次,否则再次调用会导致实现抛出一个相 应的 MessagingException 异常。 62 · getInMessage()。可被多次调用。如果 setInMessage()方法(或 setMessage(msg,�in�) )没有被调用,返回 null. 5.5.2.3.3InOptionalOut 消息交换(InOptionalOut Message Exchange) 这个子接口为�http://www.w3.org/2004/08/wsdl/in-opt-out�MEP 提供 API。 提供以下特定的 MEP 方法: · setInMessage(msg). 只能由服务消费者调用一次,否则再次调用会导致 实现抛出一个相应的 MessagingException 异常。 · getInMessage().可被多次调用。如果 setInMessage()方法(或 setMessage(msg,�in�) )没有被调用,返回 null. · setOutMessage(msg). 只能由服务提供调用一次,否则再次调用会导致实 现抛出一个相应的 MessagingException 异常。在此模式中设置�out�消 息是可选的。 · getOutMessage().可被多次调用。如果 setOutMessage()方法(或 setMessage(msg,�out�) )没有被调用,返回 null. 5.5.2.3.4InOut 消息交换(InOut Message Exchange) 这个子接口为�http://www.w3.org/2004/08/wsdl/in-out�MEP 提供 API。 提供以下特定的 MEP 方法: · setInMessage(msg). 只能由服务消费者调用一次,否则再次调用会导致 实现抛出一个相应的 MessagingException 异常。 · getInMessage().可被多次调用。如果 setInMessage()方法(或 setMessage(msg,�in�) )没有被调用,返回 null. · setOutMessage(msg). 只能由服务提供调用一次,否则再次调用会导致实 现抛出一个相应的 MessagingException 异常。 63 · getOutMessage().可被多次调用。如果 setOutMessage()方法(或 setMessage(msg,�out�) )没有被调用,返回 null. 5.5.2.3.5RobustInOnly 消息交换(RobustInOnly Message Exchange) 这个子接口为�http://www.w3.org/2004/08/wsdl/robust-in-only�MEP 提供 API。 提供以下特定的 MEP 方法: · setInMessage(msg). 只能由服务消费者调用一次,否则再次调用会导致 实现抛出一个相应的 MessagingException 异常。 · getInMessage().可被多次调用。如果 setInMessage()方法(或 setMessage(msg,�in�) )没有被调用,返回 null. 5.5.2.3.6WSDL1.1 消 息 交 换 属 性 (WSDL1.1 Message Exchange Properties) WSDL1.1 允许对操作名称的重载,在一个请求-响应消息交换(in-out 消息 交换模式)情况下,需要哪个正确的操作不能简单地由检查请求消息的类型来决 定。这种情况下,服务消费者应使用以下几个消息交换属性说明需要哪个操作: 属性名(Property Name) 属性值类型(Property Value Type) 描述(Description) javax.jbi.messaging.wsdl-11.output-type javax.xml.namespace.QName 期望的操作输出消息类型 javax.jbi.messaging.wsdl-11.output-name Java.lang.String 期望的操作输出消息名称 javax.jbi.messaging.wsdl-11.fault-types Javax.xml.namespace.QName[] 操作的故障类型 javax.jbi.messaging.wsdl-11.fault-names Java.lang.String[] 故障名称,以故障类型顺序 显示 表 5 WSDL1.1 消息交换属性 一个消费者使用上述的属性提供所有可用的信息来解决模糊性。如果消费者 无法自己解决模糊性(提供一个或多个属性),消费者发送消息交换并允许服务 提供者来解决这种模糊性。 64 例如,一个作为服务消费者的 SOAP 绑定组件,可能从一个外部服务消费者 处接收到一个请求服务名称为�foo�的操作。WSDL1.1 定义的 foo 包括: 操作�Foo�具有模糊性。如果 SOAP 组件想要使用一个上述定义的内部服 务,必须使用以下几种策略的一种来解决模糊性。 · 设置 InOut 消息交换的"javax.jbi.messaging.wsdl-11.output-type" 属性为以下任一种 tns::DoFooOutput1 或 tns:DoFooOutput2, 分别选 择第一种或第二种 Foo 操作。 · 设置 InOut 消息交换的"javax.jbi.messaging.wsdl-11.output-name" 属性为以下任一种:�foo-out1�或 �foo-out2�, 分别选择第一种或 第二种 Foo 操作。 · 设置 InOut 消息交换的非附加属性。相反,消费者依赖提供者来选择使用 哪一种�Foo�操作。 绑定组件根据特定的实现信息选择使用哪一种策略。(如 SOAP 活动 headers 或附加配置信息)。 5.5.3 查找激活端点(Querying Activated Endpoints) 服务消费者可使用组件上下文(ComponentContext)查找激活端点。(如何 使用此接口详见�框架�一章)。查找可以通过多种方式进行,但大多数返回一 个服务端点(ServiceEndpoint)对象数组。这个数组可能包含零个或多个端点; 65 消费者必须做好准备处理没有可用的服务(零个端点)情况和多个端点访问同一 类型的服务的情况。查找方法如下: · getEndpoint().方法返回一个特定的激活端点,该端点与提供的服务名称 或端点名称相匹配,如果没有匹配的则返回 null. · getEndpoints(QName interfaceName).方法返回所有实现给定的接口/端 口类型名称(interface/portType)的激活端点。接口名称参数缺省时方 法返回所有的激活端点。 · getEndpointsForService(QName serviceName).方法返回所有属于给定 服务名称的激活端点。 5.5.4 端点引用 API(Endpoint Reference API) 端点(内部或外部)在 5.1.7 节中定义,使用端点引用(EPR)在 5.4.4 节 定义。本节定义了 JBI 中处理 EPR 所需的 API。 EPR 由组件创建和解析。JBI 实现使得解析、创建、使用 EPR 的组件之间可 以交互。 组件解析接收到的一个 EPR 时需要调用 ComponentContext.resolveEndpointReference(). 组件(一般是绑定组件)解析一个它理解的 EPR 时需要实现 Component.resolveEndpointReference(). 提供可被 EPR 引用的外部端点的绑定组件使用 ComponentContext.registerExternalEndpoint()方法注册该端点,表明此外部 端点是激活的。使用 deregisterExternalEndpoint()表明外部端点不再是激活 的,并在调用 ComponentContext.getExternalEndpoints()的结果中不再显示该 端点。 66 用来生成 EPR 的组件首先选择引用哪一个外部端点。ComponentContext 提供 两种方法查找 JBI 系统中可用的外部端点: · 使用接口名称。getExternalEndpoints()返回一个实现了给定接口的所有 注册过的外部端点的数组。 · 使用服务名称。getExternalEndpointsForService()返回一个在名称服务 中包含的所有注册过的外部端点的数组。 例如,假定我们有一个服务引擎 SE1,通过一个端点 EP1 提供服务。一个该 服务的消费者是绑定组件 BC2,发布一个外部端点 EP2 供 EP1 的外部服务消费者 使用。(此时 BC2 作为一个外部消费者的代理)。 在一个用例中,SE1 发送一个请求消息给外部服务提供者,消息中提供了指 向 EP2 的回调地址(如,一个 EP2 的 EPR)。目的是让外部提供者作为一个消费 者使用 EPR 发送请求给 EP2。 在这种情景中,BC2 使用 JBI 在创建时(部署时期)注册外部端点。SE1 可 发现外部端点(使用以上的查找方法),并使用该外部端点为发送到外部提供者 的请求消息创建一个 EPR。(创建 EPR 的任务交给 BC2)。外部提供者使用 EPR 发送所需的消息给外部端点 EP2。 5.5.4.1内部 EPR 词汇(Internal EPR Vocabulary) 服务引擎提供的内部端点 EPR,如在 5.1.7 中所定义的,组件可以使用 XML Schema 来引用 EPR。这种类型的 EPR 仅在 JBI 系统中有用并可以用在内部和外部 提供的服务上。 服务引擎端点生成的引用必须符合上表所示的 schema。 67 5.5.5 应用举例(Usage Examples) 本节给出一般绑定组件、服务引擎和 NMR 交互的详细示例。运行时激活和消 息交换部分也将详细讲述。 5.5.5.1服务消费者(Service Consumer) 这是一个单个 JBI 系统内的例子。一个服务引擎,消费者引擎��外部 Web 服务的消费者(例如,对外(outbound)服务调用)。 注意: · 服务名称:{http://abc.com/services}:service1 · 端点名称:soap1 · 方向:Outbound · 操作:updateStatus(单向) · 为简单起见,服务引擎和绑定组件为单线程,在整个例子中只参与一个交 换。 · 假定以下常量已经声明: �QName SERVICE1 = new QName("http://abc.com/services", "service1"); �QName OP_UPDATE_STATUS = new QName("http://abc.com/services", "updateStatus"); �String ENDPOINT1 = “soap1”; 5.5.5.1.1服务引擎初始化(SE Initialization) 在一个组件的第一个�开始�之前,调用�init�方法进行启动前初始化。 本例中,服务引擎、传输通道和消息交换工厂已经准备好了。 68 5.5.5.1.2绑定组件初始化(BC Initialization) 在一个组件的第一个�开始�之前,调用�init�方法进行启动前初始化。 本例中,同服务引擎一样,组件创建好一个传输通道和消息交换工厂。 5.5.5.1.3消息交换(Message Exchange) 从服务引擎的角度 69 从绑定组件的角度 5.5.5.2服务提供者(服务者)(Service Provider[Servicer]) 这是一个单个 JBI 系统内的例子。一个服务引擎,提供者引擎��通过一个 SOAP 绑定组件提供一个面向外部消费者的服务(例如,对内(inbound)服务调 用)。 注意: 70 · 服务名称:{http://xyz.com/services}:service2 · 端点名称:engine2 · 方向:Inbound · 操作:getStockQuote(请求-响应) · 为简单起见,服务引擎和绑定组件为单线程,在整个例子中只参与一个交 换。 · 假定以下常量已经声明: �QName SERVICE2 = new QName("http://xyz.com/services", "service2"); �String ENDPOINT2 = “engine2”; 5.5.5.2.1绑定组件初始化(BC Initialization) 5.5.5.2.2服务引擎初始化(SE Initialization) 71 5.5.5.2.3消息传输(Message Delivery) 从绑定组件角度 从服务引擎角度 72 5.5.5.3解 析 动 态 端 点 引 用 (Resolution of Dynamic Endpoint Reference) 下表显示了一个服务消费者的解析 EPR 的例子。 5.5.5.4创 建 动 态 端 点 引 用 (Creation of a Dynamic Endpoint Reference) 下表显示了一个服务提供者创建 EPR 的例子。 5.5.6 服务提供者元数据(Service Provider Metadata) 每个服务提供者必须实现 Component 的 getServiceDescription()方法。当 NMR 要检索组件提供的服务的元数据时调用该方法,服务必须已被 NMR 激活。(使 用名称) JBI 通过特定的绑定类型对标准 WSDL1.1 和 WSDL2.0 作了补充,服务引擎使 用特定的 JBI 绑定类型声明其提供的服务端点。绑定类型将在下一小节定义。 73 5.5.6.1JBI 服务引擎 WSDL 绑定 (JBI Service Engine WSDL Binding) JBI1.0 服务引擎绑定通过给 WSDL 绑定组件的 type 属性赋以下值来标识: �http://java.sun.com/xml/ns/jbi/binding/service+engine�。 这种绑定类型用来标识服务引擎(如,JBI 系统中的本地服务提供者)。它 不能定义 WSDL 操作或消息的映射。使用所有的抽象 WSDL 定义时都无需修改。 74 6 管理(Management) JBI 系统使用 JMX 管理。包括提供特定管理接口的 JBI 组件(可插接绑定组 件和引擎)。另外,JBI 实现提供特定的 JMX 管理 Beans(MBeans)管理 JBI 系 统提供的基础设施以及 JBI 组件。再者,JBI 实现提供一套 Apache Ant 任务。 6.1 概述(Overview) 本规范支持的主要管理任务为: · JBI 的安装和共享库的安装。 · 安装组件时服务描述信息的部署(对 JBI 来说是不透明的)。 · 启动和停止组件(绑定和引擎)和 JBI 实现组件(如果可用的话)。 · 启动和停止相关服务(合成集合)。 所有这些用例假定存在着一个使用 JMX 来初始化活动的管理工具。JBI 实现 提供特定的 MBeans 对管理工具提供管理功能。这些 MBeans 是: · InstallationServiceMBean.管理工具使用此管理 bean 安装和卸载组件 和共享库。 · InstallerMBean.JBI 实现为每个组件的安装提供 InstallationServiceMBean。通过组件自己的 MBean 管理安装过程,包括 组件提供的安装配置。 · DeploymentServiceMBean.管理工具使用此 bean 为组件部署和解除部署 信息,以控制每个部署的运行时状态。 · LifeCycleMBean.管理工具使用此 bean 启动和停止 JBI 实现的模块。(此 MBean 的使用是依赖于实现的)。 · ComponentLifeCycleMBean.管理工具使用此 bean 启动和停止组件。组件 可使用组件提供的扩展 MBean 提供附加的生命周期控制。 75 另外,组件可发布它们自己的 MBean,提供除生命周期和安装扩展以外的特 定的组件管理功能。例如,组件可发布一个 MBean 管理内部日志。 安装和部署要求管理工具发送标准包给合适的 MBean。JBI 指定了这些包的 结构,包括包的标准 XML 描述符。 6.2 关键概念(Key Concepts) 6.2.1 组件安装(Component Installation) JBI 组件(引擎和绑定)使用本章定义的标准管理机制安装。此外,还定义 了为这种组件设计的标准包。目的是保证组件的轻量级,包括安装信息。组件供 应商可为分布式生产一个单独的包,而不是基于 JBI 实现目标的多个变量。通过 简化组件获取和管理后台使用户获益。 6.2.2 共享库安装(Shared-library Installation) Java 库可被多个组件共享。使用标准管理机制安装共享库。 6.2.3 部署(Deployment) 许多组件可作为容器,提供(或消费)基于组件包含的信息的服务。例如, 一个 XSLT 引擎包含多种样式表(style sheet),每种样式表提供一种特定的转 换服务。 给一个容器组件引进新的信息称为部署(deployment),引入这个名词以便 于同组件或共享库的安装予以区分。 6.2.3.1单元部署(Unit Deployment) 一个发往单个组件的部署包称为服务单元(Service Unit 或 SU)。服务单 元的内容对于 JBI 来说是不透明的(而不像描述符文件),但对于它即将部署到 76 的组件来说是透明的,同样,对设计时加工生产 SU 包含的信息来说也是透明的。 服务单元包含一个 JBI 定义的描述符文件,该描述符定义了服务单元生产和消费 的静态服务。这有助于创建合成部署。 6.2.3.2合成部署(Composite Deployment) JBI 系统中创建一个新的服务或消费者应用一般需要多种部署。JBI 提供了 合成部署的能力支持多种部署,通过部署,几个不同的组件可以组合成服务集合 (Service Assembly(SA))。服务集合包括一个合成服务部署描述符,负责服 务集合包含的每个服务单元在组件上的部署。注意,服务集合的概念有时也称 为�合成服务描述�(CSD:composite service description)。 一个服务集合代表了一个合成服务。由于这层关系,JBI 提供了管理功能, 用来从整体上对一个服务集合中的每个服务单元的生命周期进行控制。 6.2.3.3合成服务元数据(Composite Service Metadata) 部署描述符也包括了服务单元和服务提供者之间的服务连接信息,允许服务 集合的重组。这些信息分成两类: · 服务单元部署后所提供和消费的静态服务的描述。 · 服务单元和服务集合之间的静态服务互联的描述,以及与服务集合外的服 务之间的依赖关系。(如,JBI 系统内的其他服务)。 前一类允许使用工具检查静态服务间的依赖关系,并提供一个服务单元且无 需分析其内容。组件自身也可能使用这些信息来为服务单元的部署提供配置信 息。 后一类允许服务集合的设计者通过声明消费者和提供者之间的新连接,从而 改变静态服务消费者和提供者之间的连接。这些连接用来给一个提供者端点重命 名,这样当一个消费者请求某个特定的服务端点时,实际上将使用另一个不同的 端点。 77 例如,假设在一个服务集合里有如下元数据: · SU1 使用端点 EP1, · EP1 连接到 EP2。 服务集合成功部署后,如果部署了 SU1 的组件要发送一个消息交换到 EP1, 将发送到 EP2。 下图是合成服务元数据的示意图。 图 22 合成服务示例:单向消息适配器模型 上例基于�JBI 系统架构�一章所举的单向消息适配器一例。BC1 作为外部 服务消费者的代理,BC2 作为服务提供者的代理。SE2 提供转换服务,SE1 编排 整个服务,在编排的过程中同时扮演了消费者和提供者两种角色。服务集合负责 把 SE1 连接到 SE2 和 BC2 提供的服务上,把 BC1 连接到 SE1 提供的单向适配器服 务上。 78 使用合成服务元数据只是 JBI 提供的连接服务消费者和提供者的几种方法 之一。隐式端点选择、消费者动态端点选择及消息交换地址类型详见�规格化消 息路由�一章。 6.2.4 部署生命周期(Deployment Life Cycle) 特定的 JBI 接口为每个组件的部署提供了一个简单的生命周期模型。下图显 示了这个模型,同组件的生命周期类似。 图 23 部署生命周期状态图 6.2.5 组件生命周期(Component Life Cycle) 特定的 JBI 管理接口为每个组件管理一个简单的生命周期模型。组件可以添 加额外的状态信息扩展该模型。下图显示了基本的生命周期模型 图 23 基本组件生命周期状态图 组件的扩展生命周期是在基本生命周期上加上由组件的安装和卸载引入的 状态。另外,组件可以使用扩展 MBean 扩展基本的组件生命周期。例如,一个组 件可以使用扩展 MBean 提供的控制功能为�开始�状态添加一个�暂停�子状 态。 79 6.2.6 类的加载(Class Loading) JBI 实现提供类的加载器,创建组件的引导程序和组件的实现。(详见�框 架�一章)。类的加载器通过已声明的类路径访问可用的类。(参见 Java 语言 规范[JLS])(java.lang.ClassLoader)。在组件的扩展生命周期中使用两种类 型的类加载器: · 引导程序。在组件扩展生命周期中的安装和卸载阶段,组件安装方法使用 的类加载器可以访问引导程序类的路径。JBI 实现使用类加载器创建组件 引导程序(Bootstrap)的一个实例。 · 执行程序。安装完毕之后,组件进入扩展生命周期中的执行阶段。JBI 实 现为执行阶段提供的类加载器通过组件声明的类路径访问类和该组件使 用到的共享库。JBI 实现使用类加载器创建组件(Component)的一个实 例。 组件类加载器详见第七章�组件框架�。 6.2.7 使用 JMX(Use of Java Management Extensions) Java 管理扩展(JMX)提供管理设备(命令行脚本引擎、Ant 脚本、浏览器 UI 或图形化 UI)与 JBI 系统(包括 JBI 组件)之间的交互基础。JBI 实现必须 支持 JMX1.2.1 或更新的版本。 JBI 组件实现特定的 JBI(Java 语言)接口支持特定的 JBI 管理功能,JBI 实现自身提供特定的 JMX MBean 使用组件实现的接口。例如,一个管理工具使用 实现提供的 MBean 执行部署,而 MBean 使用组件提供的服务单元管理器 (ServiceUnitManager)接口部署服务单元到那个组件上。 组件提供它们自己的 MBean 执行此规范外的管理任务。关于此机制详见�组 件安装�和�组件生命周期�两节。 80 6.2.8 使用 Apahca Ant 编写脚本(Use of the Apache Ant for Scripting) Apache Ant 是 JBI 实现使用的一种标准脚本语言。Ant 任务的实现必须用到 JMX 管理接口。 6.3 包装(Packaging) JBI 为组件的安装和作为�容器�的组件的部署信息定义了标准的包装。安 装时将会用到一个描述符,部署时将会用到两种描述符: · 服务集合描述符。用来描述一个服务集合的内容。它主要描述了服务集合 中的各个服务单元所部署的位置。 · 服务单元描述符。用来描述一个服务单元提供和消费的服务。 这几种描述符的类型相似,为此引入一个简单的模型。 6.3.1 安 装 和 部 署 描 述 符 (Installation and Deployment Descriptors) 下图显示了用来创建安装描述符和两种部署描述符的模型,为清晰起见使用 RelaxNG 缩写方式。 81 82 以下的几个小节详细描述了 jbi.xml 文件的�jbi�schema 所包含产品的用 法。 6.3.1.1使用 jbi(Use of jbi) 顶层产品是�jbi�,它是 schema 生成的所有部署描述符和安装描述符的起 始点。 · Attribute version.一个十进制数值表明所用的描述符的版本信息。对于 JBI1.0 版本,此数值必须为 1.0。 · type element.表明描述符的类型,必须是以下几种之一: o component.表明描述符描述的是一个安装包。 o service-assembly.表明描述符描述的是一个部署包。 o shared-library.表明描述符描述的是一个共享库安装包。 o services.表明描述符是一个服务单元自我描述。 下面给出各种描述符类型的详细用法。 83 6.3.1.2使用 identification(Use of identification) identificaion 用来为组件、共享库、服务单元和服务集合(以下用都用条 目来表示)提供认证信息。identification 包含以下数据: · name.条目的名称,一个友好的标识符。注意,可对每种类型的条目名前 加以其它的限定(如,唯一性)。 · description. (用一个句子)对条目作较长的描述。 · extension element(可选).特定的供应商附加的额外的认证信息。JBI 不 会用到这些信息,但是创建和操纵认证包的工具需要用到附加的认证信 息。 6.3.1.3使用 class path(Use of class path) class path 用来为组件和共享库声明一个 Java 类路径。每个路径的根目录 如下: · 组件 bootstrap-class path 和 component-class path:在组件安装包的 安装目录下。详见�组件框架�一章。 · 共享库 shared-library-class path:在共享库安装包的安装目录下。详 见�组件框架�一章。 每个路径使用正斜杠(�/�)作为文件分隔符。 6.3.1.4使用 shared-library(Use of shared-library) Shared-library 用来描述共享库的安装包。由以下几部分组成: · version.表明共享库的版本信息。见组件 shared-library-list/shared-library 属性。 · identification.提供共享库的认证信息,其名称必须在 JBI 系统中所有 的安装共享库中是唯一的。 84 · shared-library-class path.声明使用共享库的组件的类路径。在 shared-library 的安装包目录下)。 另外,shared-library 有以下属性: · class-loader-delegation.如果此可选属性的值 为�self-first�,shared-library 的类加载器将反转缺省的授权模型 (�parent-first�),首先加载类加载器里的类。详见�框架�章中的� 类的加载�一节。 6.3.1.5使用 service-assembly(Use of service-assembly) service-assembly 描述服务集合的部署包,它描述了服务集合所包含的 服务单元以及这些服务单元将要被部署到的组件信息。 · identification.合成部署的唯一(在 JBI 系统中部署的所有服务集合中) 标识符。 · service-units.描述了组件上的单个部署。 · connections.(可选)包含了服务互联元数据的声明,用于把静态服务消 费者和服务提供者联系起来。 6.3.1.6使用 service-unit(Use of service-unit) service-unit 描述 service-assembly 部署包中的服务组件。 · identification.service-unit 的唯一(部署 service-units 的目标组件 中唯一)名称。 · target. o artifacts-zip.将要部署的部署包中的存档文件名。 o component-name.将要部署 artifacts-zip 的组件名。 部署过程详见�部署服务�一节。 85 6.3.1.7使用 component(Use of component) component 描述一个组件安装包。 · type.指定组件是一个服务引擎还是绑定组件。JBI 实现使用它区分两种 组件类型(为了管理查找)。 · component-class-loader-delegation. 如果此可选属性的值 为�self-first�,组件的类加载器将反转缺省的授权模型 (�parent-first�),首先加载组件类加载器里的类。 bootstrap-class-loader-delegation. 如果此可选属性的值 为�self-first�,组件引导程序的类加载器将反转缺省的授权模型 (�parent-first�),首先加载引导类加载器里的类。 · bootstrap-class path.组件的安装过程(引导)中使用的类路径。组件 安装过程详见�安装服务�。 · bootstrap-class-name.组件 Bootstrap 实现的限定类名。在组件安装过 程中会用到,详见�组件安装�。 · component-class path.组件安装之后的类路径。它与共享库类路径共同 组成了完整的类路径,通过 JBI 提供的默认类加载器上下文可直接使用组 件。详见�组件框架�一章。 · component-class-name.组件 Component 实现的限定类名。在组件生命周 期的执行阶段会用到。 · shared-library-list.提供组件使用的共享库列表(通过 name 和可选 version)。实现使用版本信息校验组件所声明的共享库版本是否与 JBI 系统中安装的共享库版本一致。 · installation extension data.组件可包含特定组件安装信息。这些扩 展元素不能放在 jbi.xml 命名空间。组件可使用 InstallaionContext.getInstallationDescriptorExtension()方法访问 这些扩展数据。 86 6.3.1.8使用 connections(Use of connections) connections 用连接元素集声明服务集合的互联元数据。这些数据声明了从 消费者提供的数据交换地址到提供者的服务端点之间的对应关系。互联元数据的 用法详见 6.6.3 节。 6.3.1.9使用 connection(Use of connection) connection 声明了从消费者提供的服务地址到提供者的服务端点地址之间 的对应关系。所有的组件在使用某项服务时都用到了这个对应关系。consumer 子元素声明对应的(连接的)消费者地址的类型。声明有两种形式: · service type.通过 interface-name 属性指定服务类型。所有被赋予给定 服务类型的交换都将发送给给定的服务提供者端点。 · service endpoint.通过 service-name 属性和 endpoint 属性指定服务端 点。所有被赋予给定服务端点地址的交换都将发送给给定的服务提供者端 点。 provider 子元素声明消费者连接的服务提供者端点。Provider 通过两个属 性声明提供者服务端点(provider service endpoint):service-name 和 endpoint-name。 6.3.1.10 使用 services(Use of services) services 声明服务单元提供和消费的静态服务。术语�static�在这里指 服务单元部署后提供或消费的服务在设计时期和部署时期是可知的。 binding-component.脱机工具可使用该属性区分服务引擎和绑定组件。它对部署 过程无影响。如果组件的类型(在安装描述符中声明的类型)与 binding-component 属性值不一致,实现会发出一个警告作为部署结果(或状态) 的一部分。 87 6.3.1.11 使用 provides(Use of provides) Provides 声明服务单元提供的服务。声明一个服务涉及到以下属性: · interface-name.限定名表明所提供服务的类型。 · service-name 和 endpoint-name.这对属性声明了部署后服务单元要激活 的端点名称。 6.3.1.12 使用 consumes(Use of consumes) Consumes 声明服务单元消费的服务。定义一个这样的服务需要使用以下属 性: · interface-name. 限定名表明所消费服务的类型。 服务单元可指定其消费的服务端点限定名。可选的服务端点名的用法见 6.6.3 节。如果声明了服务端点名,则可选择此属性。 · link-type.表明消费者希望通过连接做些什么。此属性的值可能为: o standard.默认值。根据标准规格化消息路由规则路由提供的服务 端点。 o hard.提供的服务端点名匹配服务提供者的服务端点名;不允许间 接连接。 o soft.提供的服务端点名不匹配服务提供者的服务端点名,而是匹 配一个间接的连接名。 这些值如何影响规格化消息路由详见 6.6.3 节。 88 6.3.2 安装包(Installation Packaging) 安装包包括了JBI系统安装一个JBI组件或安装一个组件使用的共享库所需 的所有东西,包括一个安装描述符,用来提供 JBI 安装服务如何处理安装包内容 所需的信息。具体的安装过程在�安装服务�中描述。 安装包是一个 ZIP 存档文件,其内容对 JBI 系统来说是不透明的,除了安装 描述符。安装描述符的命名和存放位置如下: /META-INF/jbi.xml 安装描述符文件的内容必须与组件安装描述符模型或共享库安装描述符模 型一致。 一个安装描述符的示例如下: 上例包含两个�extension�元素,使用一个属于文件元素以外的 XML 命名 空间提供特定的组件信息。JBI 实现和组件实现使用这些扩展元素提供额外的特 定的组件信息或组件加工信息。 组件供应商使用认证扩展元素提供 JBI 名称和描述以外的组件认证信息。这 些信息允许特定的组件工具识别安装包的类型,并对安装包或安装描述符进行附 89 加的操作。这些信息在组件引导起动时期和执行时期都是可获得的(jbi.xml 文 件可在安装根目录下的 META-INF/jbi.xml 找到)。 组件使用组件扩展元素在安装前提供配置信息。这种配置信息和 MBean 指定 的配置信息之间的关系由组件实现来决定。组件通过 InstallationContext 接口 获得这些信息。 6.3.3 服务集合包(Service Assembly Packaging) 服务集合包包含了对 JBI 来说不透明的部署信息,一个部署描述符,用来提 供 JBI 部署服务如何处理部署包内容所需的信息。具体的安装过程在�部署服 务�中描述。 部署包由一个部署描述符和一个或多个服务单元存档文件组成,它们都包含 在一个 ZIP 存档文件中,其文件/目录结构如下: · /META-INF/jbi.xml.包含符合部署描述符模型的部署描述符。 · /{artifacts-file-name.zip}.其中的一个服务单元存档文件名,作为部 署描述符目标元素。 · /{artifacts-file-name-N.zip}.部署描述符 jbi.xml 中提到的多个服务 单元存档文件。 一个部署描述符和部署包存放目录的示例如下。 90 部署描述符引用了部署包中的两个独立文件。这两个文件加上部署描述符组 成了一个单独的 ZIP 文件,如图 20 所示。 6.3.4 服务单元包(Service Unit Packaging) 服务单元存档文件必须包含一个单独的 JBI 定义的描述符文件: · /META-INF/jbi.xml.包含符合服务模型的服务单元描述符。 服务单元描述符提供部署到目标组件的服务单元提供或消费的服务信息。 6.4 服务安装(Installation Service) 安装服务允许管理工具从 JBI 系统中安装和卸载组件和共享库。 6.4.1 共享库安装(Shared Library Installation) 共享库的安装包可以使用 InstallationServiceMBean 安装和卸载: 91 · 安装。管理工具调用安装服务 MBean 的 installSharedLibrary()方法安 装共享库,提供安装包存放的 URL。安装包必须包含一个共享库安装描述 符。 · 卸载。管理工具调用安装服务 MBean 的 uninstallSharedLibrary()方法 卸载共享库,说明将要卸载的共享库名。要卸载的共享库名必须和安装时 安装描述符提供的库名一致。 6.4.2 组件安装(Component Installation) 组件的安装比共享库的安装稍微复杂一些。管理工具使用 InstallationServiceMBean 创建或重调用一个 InstallerMBean。 InstallerMBean 管理一个组件的安装。 InstallationServiceMBean 通过如下方式管理安装 MBean: · 创建 installer。调用 loadNewInstaller()方法,提供一个安装包的 URL。 为新创建的 installer 返回一个 JMX ObjectName。 · 重调用 installer。调用 loadInstaller()方法,提供组件名。返回的 ObjectName MBean 必须和组件安装时的返回的 ObjectName 相同。 · 卸载 installer。调用 unloadInstaller()方法,提供组件名。此方法可 以用来卸载组件。 InstallerMBean 管理组件的安装: · 安装组件。管理工具使用 install()方法安装组件。方法为新安装的组件 返回 ComponentLifeCycleMBean 的 JMX ObjectName。 · 配置 installer。安装组件之前,可使用 installer 配置 MBean 对 installer 进行配置。管理工具可使用 getInstallerConfigurationMBean()方法查找这个 MBean 的 JMX ObjectName。 · 检查是否已安装。管理工具可使用 isInstalled()方法检查 InstallerMBean 相关的组件是否已安装。 92 · 卸载组件。管理工具可调用 uninstall()方法卸载 InstallerMBean 相关 的组件。 6.4.2.1安装过程(Installation Process) 安装过程涉及到同管理工具的以下两种交互: · 使用 InstallerServiceMBean 加载 installer,为组件创建一个 InstallerMBean。 · 使用上步创建的 InstallerMBean 运行 installer。 管理工具还可能与一个安装扩展 MBean 进行交互。 以下几小节详细阐述了安装的具体步骤。 6.4.2.1.1加载 Installer(Loading the Installer) 当 InstallerServiceMBean.loadNewInstaller()方法被调用时,JBI 实现执 行以下步骤。安装步骤中的任何失误都会导致整个安装过程作废,JBI 系统将恢 复到安装之前的状态。 1. 准备安装环境。当一个 installer MBean 被创建时,安装包 ZIP 文件被解压 缩到一个安装根目录。这个根目录在组件的整个生命能够周期都会用到,并 且必须放置在一个文件系统中。类路径(来自 jbi.xml 安装描述符)对应安 装根目录下的各个条目。JBI 实现创建并初始化一个 InstallationContext 对象提供以下数据: · 安装根目录(Installation root),一个包含完整根目录路径名的字符串。 · 引导类名(Bootstrap class name),在安装描述符中给出。 · 引导类路径(Bootstrap class path),在安装描述符中给出。 · 组件名(Component name),在安装描述符中给出。 93 · 安装扩展数据。一个包含了安装描述符中的安装扩展信息的 DOM 片段。如 果描述符中没有安装扩展信息,此 DOM 片段为 null。 2. 准备引导类加载器。JBI 实现创建一个类加载器,可以访问安装包描述符中 声明的引导类路径。类加载器的描述详见第七章�组件框架�。 3. 初始化 Installer。使用上述类加载器,JBI 实现创建一个安装描述符中声 明的引导类实例。这个实例调用 init()方法初始化引导程序,并把它传给第 1 步准备好的安装环境。此时 ,组件提供的引导程序可以使用组件环境中的 JMX 服务器注册一个安装扩展 MBean。 4. 创建 Installer MBean。引导程序调用 init()方法后,JBI 实现为组件创建 并注册一个 InstallerMBean。注意,InstallerMBean 需要到引导加载器对 象和安装环境的引用来完成安装。 6.4.2.1.2自定义安装(Customized Installation) 加载 installer 之后,管理工具从 InstallerMBean 接收一个 JMX 对象名。 管理工具使用 InstallerMBean 的 getInstallerConfigurationMBean()方法检查 InstallerConfigurationMBean 是否存在。如果不存在,需要在管理工具运行 installer 之前使用 InstallerConfigurationMBean 进行自定义安装。 6.4.2.1.3运行 Installer(Run Installer) 加载 installer 之后,管理工具从 InstallerMBean 接收一个 JMX 对象名。 管理工具调用 InstallerMBean 的 install()方法完成安装。JBI 实现执行以下步 骤以完成安装。 1. 调用引导对象的 onInstall()方法。 2. 调用引导对象的 cleanUp()方法。此时引导程序对任何先前注册过的 MBean 撤销注册。 成功调用 install()将返回 ComponentLifeCycleMBean 的 JMX 对象名。 ComponentLifeCycleMBean 用来控制组件的运行状态。见�组件生命周期�。 94 6.4.3 组件卸载(Component Uninstallation) 使用 InstallerMBean 卸载组件,卸载过程是安装的逆过程。注意,卸载时 使用的引导类实例并不保证一定是组件安装过程中使用的那个。 注意,如果引导程序的 init()方法注册了一个扩展 MBean,引导程序的 cleanUp()方法就会撤销注册。 6.5 组件生命周期(Component Life Cycle) 每个组件的生命周期都: · 从使用 InstallationServiceMBean 安装组件开始。组件的状态为�已安 装�。组件的所有执行状态都可以看作是�已安装�状态的子状态。 · 通过 ComponentLifeCycleMBean 控制,对于自定义生命周期子状态,还可 能会用到一个生命周期扩展 MBean。 · 通过组件使用 ComponentLifeCycle SPI 实现。详见�框架�一章。 · JBI 实现提供 ComponentLifeCycleMBean,它与组件 SPI 实现共同控制组 件生命周期中的各个状态。 每个已安装的组件都有一个最小生命周期,如图所示。 图 25 组件生命周期状态图 95 最小生命周期使用两种 JBI MBean:InstallerMBean,控制是否安装组件到 JBI 系统。(如,已安装状态);ComponentLifeCycleMBean,控制更常规的组件 开始/停止生命周期。组件可以通过一个生命周期扩展 MBean 来扩展常规生命周 期,扩展 MBean 提供额外的生命周期状态。图 26 在标准�开始�状态上加了一 个�暂停�子状态。通过使用扩展 MBean 提供的�暂停�控制访问这个附加的子 状态。 图 26 扩展组件生命周期状态图 管理工具通过ComponentLifeCycleMBean和生命周期扩展MBean改变组件的 运行状态。组件 ComponentLifeCycle 接口的实现提供执行状态转换的具体逻辑。 JBI 实现负责: · 维持组件的基本执行状态。 · 将 ComponentLifeCycle 方法的调用进行排序以保证基本执行状态的合法 转换。例如,如果管理工具调用 start()MBean 控制一个处于关闭状态的 组件,实现必须按照顺序调用 ComponentLifeCycle 的 init()和 start() 方法。组件生命周期方法详见�框架�一章。 96 注意,如果 JBI 系统重新启动,JBI 实现要把所有的组件都恢复到重启前的 运行状态。如果组件希望用一种不同的方式重启,扩展�开始�状态,必须提供 一套机制来维持扩展的运行状态,并在 JBI 重启组件的时候恢复先前的运行状 态。所有的生命周期扩展都是开始状态的子状态。详见�框架�一章。 组件 Bootstrap 的实例在使用前必须先调用它们的 init()方法。在组件的 扩展生命周期中可以使用不同的 Bootstrap 实例。当 JBI 实现使用 Bootstrap 实例结束时,调用实例的 cleanUp()方法。 下图显示了安装过程中协作的参与者之间的交互顺序,包括配置扩展 MBean 的用法。图中描述了各操作的逻辑顺序。JBI 和组件实现可以改变这个顺序,只 要保留了逻辑上的排序。 图 27 安装过程消息序列图(带有扩展 MBean) 这个过程是由管理工具驱动的。管理工具使用 InstallationServiceMBean 创建一个新的 InstallerMBean 实例。Installer 使用这个新的 installer MBean 访问扩展 MBean,在继续安装之前配置 Bootstrap 对象。最后,管理工具启动真 正的安装过程:InstallerMBean 释放安装包的内容并按顺序调用 Bootstrap 对 象的 onInstall()和 cleanUp()方法。 注意,对扩展 MBean 的注册和撤销注册需要用到 MBean 服务器,图中为简单 起见省略了 MBean 服务器。组件使用 Bootstrap 的 init()方法或 97 getExtensionMBean 方法创建并注册 MBean。无论使用哪种方法,都要使用 cleanUp()方法对扩展 MBean 撤销注册。 还要注意,管理工具不一定非要调用 InstallerMBean 的 getInstallerConfigurationMBean()方法。必要的话管理工具会忽略这一步。(例 如,管理工具可能事先知道 installer 没有这样一个 MBean,或者即使扩展 MBean 存在管理工具也没有办法处理它。) InstallerMBean 对其自身执行的�释放�一步描述的是将组件安装文件的 内容解压到为其分配的根目录下的过程。 卸载的过程同安装类似,如下图所示。 图 28 卸载过程消息序列图(带有扩展 MBean) 注意,Bootstrap 对象创建、注册、撤销注册了扩展 MBean。还要注意卸载 的过程中,Bootstrap 对象的 onUninstall()方法要在�整理�(clean up)之 前调用(整理的过程是释放的逆过程)。在安装过程中正好相反,Bootstrap 对 象的 onInstall()方法要在�释放�后调用。之后,调用 Bootstrap 对象的 cleanUp()方法,引导程序释放占用的所有资源,如扩展 MBean 的注册。最后, 对安装服务 MBean 调用 unloadInstaller()方法,此时实现注册并清理先前创建 的 installer MBean。 98 6.6 服务部署(Deployment Service) 部署服务允许管理工具把服务集合部署和解除部署到 JBI 系统,或从 JBI 系统中把服务集合部署和解除到其他地方,并控制这些服务集合的运行状态。 部署由服务集合组成,详见�服务集合包装�一节。管理工具调用 DeploymentServiceMBean 的 deploy()方法请求一个服务集合的部署,为服务集 合包的资源传递一个 URL。服务集合包必须符合�服务集合包装�一节中的要 求,否则无法部署服务集合中的任何服务单元(抛出 java.lang.Exception 异 常)。 注意,一个”复制”的服务单元指的是: · 和先前部署到组件中的服务单元有相同的名字。 · 和先前部署到组件中的服务单元有相同的内容(服务单元具有同样的长度 和同样的二进制数据)。 JBI 实现必须能够发现这些复制品。部署一个和先前已部署过的服务单元同 名的非复制服务单元会出错,而重部署一个复制的服务单元不会出错。 当�部署�方法接收到一个有效的部署包时,JBI 实现做出以下处理步骤: 1. 确认部署包,确保部署描述符符合 6.3.3 节的要求。同时确保部署包中包含 所有的服务单元信息,所有指定的目标组件都已安装到 JBI 系统中。 2. 对部署描述符中的每个: · 解压服务单元描述信息文件到文件存储空间。(如果同一个部署描述符中 服务单元被部署到多个组件上,服务单元必须被复制,这样一个组件对部 署内容做出改动不会影响到其他的组件上的部署信息)。 · 把指定的服务单元部署到指定的组件。详见�服务单元部署过程�一节。 如果步骤 2 的任何一次重复不能把指定的服务单元部署到指定的组件过程 中,实现必须继续部署服务集合中剩余的服务单元。如果服务集合中的所有服务 99 单元都没有部署成功,抛出一个部署失败的异常。如果至少有一个服务单元部署 成功,调用 DeploymentServiceMBean 的 deploy()方法,使用状态返回的字符串 报错。该字符串的格式在 6.9 节中规定。 如果服务单元的部署是一个复制,部署被跳过而不是作为一个部署错误。这 样,服务集合会重新部署而不会打扰现有的部署。 DeploymentServiceMBean 还用来控制服务集合的生命周期,见 6.8 节。 6.6.1 服 务 单 元 部 署 过 程 (Service Unit Deployment Processing) 本节详述了如何部署一个服务单元。JBI 实现保存服务单元信息。对每一个 服务单元,JBI 实现对非复制的服务单元部署执行以下操作。执行的顺序同服务 单元在服务集合描述符中声明的顺序一致。 1. 查找目标组件的 ServiceUnitManager 接口。注意,组件(而不是 JBI 实现) 提供该接口,JBI 实现调用组件的 Component.getServiceUnitManager()方 法查找该接口。 2. 实现为每个服务单元分配资源,包括服务单元部署的文件存储空间。 3. 实现解压(�释放�)服务单元的内容到为其分配的存储空间根目录下。 4. 实现使用 ServiceUnitManager 接口的 deploy()方法,提供部署描述符中声 明的服务单元名以及服务单元描述信息的根路径名,从而部署服务单元描述 信息到组件上。 此时,服务单元部署已完成,并开始生命周期管理。详见�6.7�节。第一 次安装,服务单元(及其所在的服务集合)处于�关闭�状态。 100 6.6.2 服 务 集 合 撤 销 部 署 过 程 (Service Assembly Undeployment Processing) 服务集合在可以撤销部署之前必须处于关闭状态。服务集合使用 DeploymentServiceMBean 的 undeploy()方法撤销部署,undeploy()使用将要撤 销部署的服务集合名作为参数。对指定的服务集合中的每个服务单元,JBI 实现 执行以下操作。操作的顺序与服务集合描述符中服务单元声明的顺序正好相反。 1. 查找目标组件的 ServiceUnitManager 接口。注意,组件(而不是 JBI 实现) 提供该接口,JBI 实现调用组件的 Component 接口实现的 getServiceUnitManager()方法查找该接口。 2. 实现使用 ServiceUnitManager 接口的 undeploy()方法,提供部署描述符中 声明的服务单元名以及服务单元描述信息的根路径名,从组件上撤销服务单 元的部署。 3. 实现释放分配给服务单元部署的资源,包括服务单元存放的根目录下的存储 空间。 6.6.3 连接元数据处理(Connection Metadata Handling) 服务集合包含连接元数据:描述消费者提供的服务地址到服务提供者端点地 址之间的映射的数据。映射影响 NMR 如何路由消费者和提供者之间的消息交换。 (详见�规格化消息路由�一章)。连接元数据可通过操纵现存的服务单元合成 新的服务集合,还可用在管理方面。 JBI 实现使用服务集合部署描述中的连接元数据,创建服务连接��执行规 格化消息路由时 JBI 实现必须用到的映射。(其过程详见�规格化消息路由�一 章) 服务连接的逻辑结构包含两个地址: · 消费者地址。一个由服务消费者提供的地址,有两种形式: 101 o 服务类型名。消费者通过接口名指定希望获得的服务类型。 o 服务端点名。消费者通过限定名指定希望获得的服务端点。 · 提供者端点地址。发送消息交换给消费者地址的实际提供者的地址。 6.6.3.1链接类型(Link Types) 规格化消息路把消息交换从发起的消费者处发送至一个提供者。有时消费者 可能希望管理服务连接如何路由它发起的消息交换。用术语�提供者链接类型� 来描述这种情况。有三种可能的提供者链接类型: · 标准链接。NMR 执行正常路由,包括使用服务连接。 · 硬链接。消费者一般直接指定提供者的端点,路由不受服务连接的影响。 换句话说,消费者要求给定的端点地址必须是一个内部端点。 · 软链接。消费者使用一个间接地址指定提供者端点。此时消费者提供一 个�假�(并不存在的)端点。这种类型的链接是消费者的一个声明:给 定的地址必须使用一个服务连接来解析。如果该端点是一个内部端点的话 就会引发错误。 6.6.3.2服务单元和规格化消息路由(Service Units and Normalized Message Routing) 服务单元包含它所提供和消费的静态服务的元数据。这些数据主要用来合成 (或分解)服务集合。服务单元为所消费的服务声明了一个特定的属性,该属性 影响 JBI 实现如何处理链接。这个属性就是消费者元素中的 link-type,用来指 定一个服务单元的消费者服务链接类型。各种链接类型在 6.6.3.1 节定义。 JBI 实现在部署一个服务单元时必须读取该服务单元部署描述符并收集所 有的链接类型声明。这些将影响到服务单元部署的组件发起的消息交换如何进行 规格化消息路由(详见�规格化消息路由�一章)。JBI 实现在服务集合启动之 前必须收集部署相关的所有服务连接和链接类型信息并使其生效。在服务集合停 止或关闭之后 JBI 实现挂起该服务集合中所有的服务连接。 102 6.7 服务单元生命周期(Service Unit Life Cycle) 每个服务单元部署都有一个生命周期,允许它启动、停止等。图 29 描述了 这样的一个状态图。生命周期模型的具体解释是依赖于组件的,但总的来说组件 解释一个部署的启动状态(Started state)作为服务提供和消费活动的开始, 而停止状态(Stopped state)表示服务的消费活动已终结,关闭状态(Shutdown state)表示服务的提供和消费活动都已终结。一个部署的生命周期状态就是它 的执行状态。 图 29 服务单元(SU)生命周期状态图 服务单元部署群的启动分两个阶段以确保 JBI 系统有序地启动。任何部署群 在启动或重启时,JBI 实现为群里所有的服务单元部署在调用 start()之前调用 init()。 JBI 实现保存所有服务单元部署的执行状态,这样系统可以从关闭或崩溃中 重启,且所有的部署都将恢复到之前的运行状态。组件重启过程中,实现执行以 下操作使得服务单元恢复到之前状态: · 启动(Started)。实现调用 init(),然后调用 start(). · 停止(Stopped)。实现调用 init()把一个服务单元恢复到停止状态。 · 关闭(Shutdown)。实现调用 init(),然后调用 shutDown()把一个服务单 元恢复到关闭状态。 103 无论哪种状态恢复,实现在调用其它生命周期的方法之前首先调用 init()。 6.8 服务集合生命周期(Service Assembly Life Cycle) 每个服务集合都有一个生命周期,同服务集合中的服务单元的生命周期类 似。图 30 描述了这样一个状态图。 图 30 服务集合生命周期状态图 每个服务集合通过管理工具使用 DeploymentServiceMBean 管理其生命周 期: · start(serviceAssemblyName)方法将启动服务集合中当前状态不是启动 (Started)的每个服务单元。如果服务单元处于关闭(Shutdown)状态, 实现首先对这些服务单元调用 init()。 · stop(serviceAssemblyName)方法将停止服务集合中当前处于启动 (Started)状态的每个服务单元。 · shutDown(serviceAssemblyName)方法将关闭服务集合中当前未关闭的 服务单元。对所有处于启动状态的服务单元,实现在试图关闭这些服务单 元之前首先停止它们。 当处理上述管理命令时,如果任何试图改变服务单元的运行状态失败了,错 误 必须用返回状态/结果字符串报错(其格式详见 6.9 节)。 104 注意,每个服务单元的运行状态由 ServiceUnitManager 的生命周期管理来 控制。访问每个组件的 ServiceUnitManager 见 6.6.1 节。 6.9 MBean 状态和结果字符串(MBean Status and Result Strings) 很多 JBI 管理 bean 的方法要求使用一个字符串状态/结果代码,用来传达执 行特定的管理任务后的结果,包括出错信息。本节定义这种字符创的格式。使用 符合以下模型的序列化 XML 文件,作为 Java 字符串传递,传达调用 JBI 实现 MBean 的某些管理方法后的状态和结果。 这种方法有许多优点。使用 XML,避免了在分布式环境尤其是使用 JMX 时的 同步类定义问题。另外,XML 易操作,允许管理工具充分利用结果、出错信息显 示、日志结果等信息。 105 组件使用的模型结构如下: · jbi-task 与文件命名空间一起的文件元素,标识本文件为一个 JBI 管理 任务结果/状态报告。 · jbi-task-result 报告实现执行任务的结果,以及执行任务的组件部分的 结果。后者只在特定的情况下出现(任务涉及到与一个组件交互,任务进 行到交互开始的那一点)。 · frmwk-task-result 报告实现执行任务的结果。包括一个可选的元素, is-cause-framework,当 JBI 实现造成任务不能执行时,该元素被设置 为�Yes�。 106 · frmwk-task-result-details 用来包含一个详细的任务报告以及报告所 处的位置信息(支持 I18N/L10N)。 · component-task-result 报告与组件的交互结果。包括组件的唯一名和组 件任务结果的详细信息。例如,组件的 ServiceUnitManager 实现使用它 返回 deploy()和 undeploy()的结果。 · component-task-result-details 报告组件执行的任务结果的详细信息。 · task-result-details 报告任务 ID、结果(SUCCESS 或 FAILED)、某种类 型(ERROR、WARNING 或 INFO)的消息。可包含零个或多个任务状态消息 (处理组件间的多个交互)。最后,还可提供异常信息。 · msg-loc-info 使用一种格式化字符串和零个或多个文本参数来报告一个 消息。其结构支持 I18N/L10N。 o loc-token 用来寻找消息的本地化信息的消息密钥。 o loc-message 默认的消息。所有的消息都必须使用 java.text.MessageFormat 格式定义消息以及消息中参数的位置。 o loc-param 消息的零个或多个参数。 · exception-info 报告异常,包括以下条目: o nesting-level 用整型数值表明该异常在一个嵌套的异常中所处 的层次。 o msg-loc-info 报告异常消息值。 o stack-trace 报告抛出异常的点的栈追踪。 下图显示了一个部署错误的例子。 107 本例中,错误是由 JBI 实现(框架)发现的一个畸形的部署描述符而引起的。 组件提供状态/结果字符串作为 XML 字符串,符合 component-task-result-details 类型。例如,ServiceUnitManager.deploy() 方法返回这样一个状态/结果字符串。JBI 实现把组件提供的状态/结果字符串合 成为一个整体的状态/结果文件。 6.10 Ant 脚本支持(Ant Script Support) 略。 108 7 组件框架(Component Framework) JBI 组件(包括服务引擎和绑定组件)将 JBI 提供的接口封装之后,向外界 提供调用 JBI 的接口。JBI 和组件间的主要消息和处理机制已将在前面章节中讨 论过了,本章将详细论述组件的框架。 JBI 实现基于底层的 Java 环境,建立了一个组件环境。JBI 框架为使用组件 提供了以下的功能: · 组件安装环境(Component installation context):为实现组件初始 化必须提供的功能,它使组件在安装和卸载的时候可以访问 JBI 所提供的 资源和组件安装信息。 · 组件环境(Component context):为实现组件初始化必须提供的功能, 它使组件在正常执行的时候可以访问 JBI 所提供的资源。 · 加载类(Class loading):JBI 保证用来创建组件中的初始化类和成员 类实例的类加载器可以在初始化和执行时正确的设置。这使组件可以访问 标准的类加载器、组件和 JBI 库。 · 错误提示(Error indication):异常类为 JBI 指定的组建错误给出提示, 使组件可以区分不同的错误类型。 另外,组件还为实现以下功能提供了特别的接口: · 引导程序(Bootstrap):在 JBI 的安装(卸载)配置功能之外提供了扩 展的功能。 · 组件管理接口(Component):该接口所提供的方法可以用来调用组件的 生命周期接口,提供服务元数据,调用组件的服务单元管理器。 · 组件生命周期接口(Component life cycle):提供组件的生命周期控 制。正如第六章中所述,它可以被 componentLifeCycleMBean 所使用。 · 服务单元管理器接口(Service unit manager):将服务单元部署到组 件上,并进行生命周期控制。这是一个可选的接口,不用部署的组件无需 提供此接口。 109 以上这些功能都是与管理活动有关的,如果想更深入了解它们是怎样被使用 的请参照第六章内容。 7.1 组 件 提 供 的 管 理 功 能 (Component-Supplied Management Functions) 7.1.1 引导程序(Bootstrapper) 组件的安装组要是由 JBI 管理系统来处理的(详情参看第六章),它将安装 镜像复制到 JBI 实例的文件系统中。安装(或卸载)组件的过程可以由组件来订 制,这使得可以在复制管理系统提供的二进制镜像之外执行更进一步的安装处 理。例如,在组件初始化阶段可执行在数据库中创建表的操作。 在组件的安装包中必须提供实现 Bootstrap 接口的类的名字,这个名字必须 是严格符合命名要求的(关于安装包的详细内容参见第六章)。在安装或卸载组 件之前,一定要创建并初始化一个在安装包中指定的 Bootstrap 类的实例(通过 调用 Bootstrap.init ( )方法),详细说明见第六章。 7.1.2 组件接口(Component Interface) 每个组件都必须实现一个组件接口,用以实现这一功能的类的名字是通过安 装描述符的形式提交给系统的。此描述符在第六章中介绍。 本章中讲述了 JBI 实现是怎样利用组件接口这一独立的功能来对其他组件 接口的进行查找的。通过组件接口可以访问以下资源: · 组件的生命周期记录,具体过程将在后续内容介绍。 · 组件服务单元管理器,可部署的组件需要提供。建议在组件每次调用服务 单元管理器的 getServiceUnitManager ( )方法的时候,不要返回 null, 而是返回一个与服务单元管理器类型相同的实例。 110 在组件初始化之后,为了对其进行更进一步的管理,JBI 必须获得一个实现 了该组件接口的实例。可遵循以下原则创建一个 javax.jbi.component.Component 的实例来完成。 · 类名必须采用�组件-类-名字�的形式,正如在组件安装描述符中声明的 那样。 · 必须用组件类加载器创建。 JBI 实现在组件启动或重起时,必须创建该组件的一个实例,并且只能创建 一个。 7.1.3 组件生命周期(Component Life Cycle) 每个组件都必须实现 ComponentLifeCycle 接口,JBI 可以通过 Component 接口访问它。 应注意这里的生命周期与通过 ComponentLifeCycleMBean 提供给管理工具 的生命周期不同。JBI 为实现这个 MBean 必须利用 ComponentLifeCycle 接口将 组件的状态做必要的转换。关于组件的 MBean 生命周期的详细讨论见第六章。 组件在安装之后就可以进行常规的生命周期控制。组件的基本生命周期状态 以及状态键的转换如下图所示。注意�Paused�和�Running�两个扩展状态是 对基本 JBI 实现的生命周期状态的扩充,所有的扩展状态都是标准状 态�Started�的子状态。 组件在第一次安装之后处于�Shutdown�状态。在使用组件提供的除了初始 化之外的其他服务之前,必须先得到并初始化组件的生命周期记录。这必须使用 javax.jbi.component.Component 来实现。JBI 一定要获得该组件的 ComponentLifeCycle 对象。 111 图 31 带有扩展子状态的组件生命周期状态图 当组件处于�Shutdown�状态时,调用 LifeCycleMBean.start()方法,就 会使 JBI 调用将该组件生命周期初始化的 init()方法,并向其传递一个有效的 组件环境,然后调用生命周期的 start()方法,如下图所示。初始化之后,再调 用start()方法须在�Stopped�状态之下,但此时不会再使JBI框架调用init() 方法,并且不会对停止和关闭操作产生影响。 图 32 初始化组件起始消息序列图 112 图 33 组件重启消息序列图 JBI 必须保留在最初开始阶段或其他需要的时候所创建的 Component 对象, 通过它来访问组件的生命周期等组件信息。 7.1.3.1系统重启(System Restart) 所谓系统重启就是指在系统关闭或崩溃之后再重新启动的操作。重启时,JBI 实现必须保存每个组件的运行状态以便将其尽量恢复到重启前的运行状态。 所有组件扩展状态都被认为是�Started�状态的子状态。当组件处 于�Started�状态重启时,必须将所它的扩展子状态保存起来。 7.1.4 服务单元管理(Service Unit Management) 组件以实现 ServiceUnitManager 接口的方式提供服务单元管理的功能,如 果一个组件未实现此功能那就意味着它并不打算部署的服务单元上。 在服务部署阶段,JBI 实现必须调用 ServiceUnitManager 方法,正如第六 章所述的那样。 113 7.2 JBI 环 境 的 特 性 (JBI-Supplied Environment Features) 7.2.1 组件上下文(Component Context) ComponentContext 接口使组件可以查找其所在的运行环境中由 JBI 所支持 的一些功能。这些可供组件生命周期接口通过 init()方法调用。 运行环境必须支持以下这些功能: · 组件名(Component Name):在组件安装时必须为其指定唯一的名字。 · 安装根目录(Installation Root):组件的安装根目录。 · 工作空间根目录(Workspace Root):可以被组件随意使用的文件空间的根 目录。 · MBean 命名服务(MBean Naming Service):为组件中 MBean 所产生的 JBX MBean 对象起名。 · MBean 服务器(MBean Server):用于注册 JBI 系统中的所有 MBean。 · 命名上下文环境(Naming Context):可供组件使用的 JNDI 命名上下文环 境。 · 传输通道(Delivery Context):提供引擎与消息路由器的交互通道,参见 第五章。 · 端点激活/解除激活(Endpoint Activation/deactivation):允许组件声 明他所提供的端点是否可供 JBI 环境中的消费者使用。参见第五章。 · 端点注册/撤销注册(Endpoint Registration/deregistration):允许绑 定声明外部端点是否可作为外部端点引用。参见第五章。 另外,运行环境还提供以下的功能用于与 NMR 交互。 · 将组件所提供服务的端点激活或撤销激活。 · 为某个特殊的借口活或服务查找可用的端点。 114 7.2.1.1查找元数据(Querying Metadata) ComponentContext 接口允许组件查找 JBI 系统所提供的元数据服务。此功 能可用来支持动态服务发现和选择服务提供者。 · getEndpoints()方法:JBI 实现必须能列出所有的支持指定接口类型的端 点。 · getEndpointsForService()方法:JBI 实现必须能列出所有的提供指定服 务的端点。 · getEndpointDescriptor()方法:JBI 实现必须能返回给定端点的元数据 描述符。 · getExternalEndpoints()方法:JBI 实现必须能列出所有的被注册为可以 提供指定接口类型的外部端点。 · getExternalEndpointsForService():JBI 实现必须能列出所有的被注册 为可以提供指定服务的外部端点。 只要找到端点的描述符(Descriptor),就可以使用 getDescription()方法 得到服务元数据(端点的 WSDL 描述),该方法的返回值是 DOM 形式的端点描述。 7.2.1.2端 点 激 活 和 解 除 激 活 (Endpoint Activation and Deactivation) 作为服务提供者的 JBI 组件必须将目前可用的端点告诉 NBR(一个组件可支 持多个端点)。这样的组件可以用下面的 ComponentContext 方法动态的(随意 的)将端点激活或解除激活。 · activateEndpoint (serviceName, endpointName)方法:组件可使用此方 法告知 NMR 哪个已命名的端点可以被用来处理消息交换。但组件在调用该 方法之前必须先预备好要向该端点提供服务数据,并准备好处理由该端点 传输的消息。 115 · deactivateEndpoint(endpoint)方法:组件可以使用此方法告知 NMR 已经 从服务中提取出一个命名好的端点。在端点被停用之后它的服务便不可再 调用。此时正在传输的消息将会等待后续的处理。 7.2.2 安装(引导)(Installation[Bootstrap]) 安装的全过程已经在第六章中介绍。在整个安装过程中,JBI 实现利用安装 上下文环境信息(InstallationContext)来初始化组件。安装上下文环境提供 了安装和卸载组件时所需的系统环境信息(安装上下文环境信息可供 Bootstrap 对象的 init()方法调用)。 7.2.2.1安装上下文环境(Installation Context) 为了使组件在初始化阶段能够访问 JBI 环境中的关键资源,Bootstrap 方法 被传输给 InstallationContext 接口。安装上下文环境必须能够访问以下一些资 源: · 组件名(Component name):在安装描述符中为组件指定的唯一的名字。 · 组件类名(Component class name):实现组件 SPI (javax.jbi.component.Component)的类的名字。它可在组件初始化时 读出和写入,最初应按组件安装描述符提供的�组件-类-名字�的形式设 置。 · 类路径元素(Class path elements):组件执行时所需 jar 文件的路径列 表。并且实现 Component SPI 的类也必须位于此路径上,以便在组件初始 化阶段访问。最初应按组件安装描述符提供的�组件-类-名字�的形式设 置 · 组件上下文环境(Component context):JBI 组件的全局环境。与通过组 件生命周期的 init()方法访问组建上下文环境类似,只不过它是全局的 可供所有安装环境实例访问。在安装阶段可访问它的方法有: ComponentName(), getInstallRoot(), getMBeanNames(), 116 getMBeanServer(), getNamingContext(), getTransactionManager()。 调用其它方法一定会返回 null 值或 JBIException。 · 安装根目录(Installaion root directory):组件安装的根目录的完整 路径。 · 组件安装描述符(Component installation descriptor):支持对安装描 述符(jbi.xml)扩展数据的访问,具体已在第六章中安装包部分讨论过。 它允许在初始化时访问扩展的安装信息。 除非另有声明,否则这些属性必须为只读的。 在安装时可以使用 setter 方法改变类的路径。 7.2.3 日志(Loggers) 组件可以使用 ComponentContext 创建一个标准的 java.util.logging.Logger 实例。getLogger()方法有两个参数:一个附加字符 串(可以为空),一个指定资源的名字(可以为空)。getLogger()方法必须保 证以下几点: · 组件的记录名字必须是唯一的。创建组件时所起的名字一定不要和已有的 组件名或 JBI 实现内部所使用的记录名相冲突。 · 在同一组件内使用同样附加字符串调用 getLogger 方法,必定会返回同样 的记录示例。 参数中的指定资源的名字如果不为空的话,那就意味着一定是用该资源创建 了该记录实例,由此就能够将日志信息定位。在初始化组件的类加载器时,该资 源一定可以被加载(它一定是在组件本身的类路径上或共享库中)。下面的 7.3 节将介绍 JBI 环境加载类和资源的细节。 117 7.3 类的加载(Class Loading) JBI 实现须为在安装和执行时创建最初的,由组件提供的对象而提供类加载 器。本部分将会详细讨论类加载器怎样保证在所有 JBI 实现上的加载类操作的一 致性,而这种一致性是实现组件可移植性的关键。 在组件的生命周期中分别有两个阶段需要使用两种不同的类加载器: · 安装阶段(Installation time)。组件必须实现在安装描述中所指明的初 始化类,JBI 实现须使用初始化类加载器来创建初始化实例。 · 执行阶段(Execution time)。组件必须实现在安装描述中所指明的用来实 现 Component 接口的组件类,JBI 实现须使用执行类加载器来创建这个组 件类。 两种类型的类加载器都必须提供以下资源: · 适当的平台类和资源 · JBI 类 · 在类路径上可访问的类或资源: o 在初始化类加载器中,类路径是指组件安装描述中指明的初始化类 路径; o 在执行类加载器中,类路径是指组件的安装上下文环境 (InstallationContext)中提供的类路径。 在后面的 7.3.2 节中还会提到执行类加载器还额外提供了共享库。 7.3.1 类 和 资 源 的 加 载 方 式 和 加 载 器 排 序 (Class and Resource Loading Styles and Loader Ordering) Java2 的类加载器可以被用来加载 Java 类和资源。类加载器可以有其父类 加载器,由此多个类加载器可以形成一个有序的层次结构。类加载器通常会先让 118 它的父加载器去加载某个类(或资源),如果失败了,自己再去加载那个类(或 资源)。JBI 的术语将此行为称作�优先授权父类加载器�。 另一方面,在有些情况下也需要与此相反的行为,JBI 术语称为�优先授权 自身加载器�。这是由组件和共享库的安装描述中的配置数据所控制的。当类加 载器被调用时,是先授权给父加载器还是先自己处理,取决于它的授权方式。 · 优先授权父加载器方式(parent-first):加载器必须先调用它的父加载 器。只有父加载器无法加载时,它才会去亲自加载。 · 优先授权自身加载器方式(self-first):加载器先亲自去加载类(或资 源),如失败再去调用父加载器。 由于这两种类加载器的优先授权方式不同,导致类加载器之间的调用顺序和 各个加载器去试图加载某个类或资源的顺序并不相同。如果所有的类加载器都采 用优先授权父加载器的方式,那么当某个子类加载器加载某个类或资源的时候, 就会自底向上逐层授权给父类加载器,而最终会由此层次结构中的根节点��组 件类加载器最先去试图进行加载。 即便一个类加载器采用优先授权自身加载器的方式,在它加载一个完整类名 是以�java.�或�javax.�开头的类的时候,也一定要采用优先授权父加载器 的方式。 当装载一个类时,第一个被调用的类加载器被称作�起始类加载器�。而真 正将该类加载的加载器被称作�定义类加载器�。类加载器的顺序规则会决定调 用的顺序,也就是说,授权方式会影响类加载器加载类的实际顺序。 7.3.2 共享库(Shared Libraries) JBI 组件间的联系是很松散的,甚至可以只通过 MessageExchange 和 NormalizedMessage 接口交互。在一些重要的应用案例中,还需要另外利用 NormalizedMessage 属性交互,在该属性中有一个共享的类集,用来读写消息属 性。例如,EDI 绑定组件需要共享一个专门的类对象集,它定义了一个描述了一 119 个专门服务引擎的 EDI 文档。绑定的组件的安装是独立于引擎的,二者如需共享 一个通用库就需要实现共享类和共享类加载器。这需要 JBI 环境在执行类加载器 的层面上为这样的共享类和类加载器提供支持。 为了使组件只能能够以一个可控的、可预见的方式共享类加载器,并且不会 对其他系统组件造成不利影响,需要提供一个 JBI 环境下的特殊的类加载方案。 接下来的执行类加载器部分将会对此进行描述。 7.3.3 执行类加载器(Execution Class Loader) 执行类加载器由一系列加载器组成,用来加载组件所需的不同的类和资源。 此节将会对此进行描述。另外,执行类加载器还必须遵守随后将要介绍的顺序规 则。 JBI 实现必须为每个组件提供一个单独的组件类加载器,这个加载器可以访 问组建安装描述文件中声明的类路径上的类和资源。当组件加载器会顺序的按照 安装描述文件中声明的类路径来搜索类或组件。执行类加载器必须是 JBI 实现用 来创造组件声明的 Component 类实例的初始化类加载器。 共享类加载器可以访问独立于组件安装的共享库,需强调的是组件可以利用 他们来共享基于非标准的类和接口所创建的对象。这使共享类加载器所加载的类 创建的对象具有唯一的命名空间。由于属于独立的命名空间,Java run-time 会 认为由不同的类加载器所加载的类创建的对象是不同类型的,甚至由同一 个.class 源文件创建的不同对象也是如此。共享类库加载器必须按照安装描述 文件中的顺序搜索共享库。 JBI 类加载器必须被用来加载 JBI 类。如果平台类加载器或内置的类加载器 没有实现 javax.xml.namespace.QName 类的话,则 JBI 类加载器必须将它实现。 一些运行环境提供了可加载共享平台类的平台类加载器。对于一些环境来说 这是非常实用的,比如在应用服务器中提供可加载除虚拟机内之类以外的类的加 载器。 120 7.3.3.1类的加载顺序规则(Class Loading Ordering Rules) 本节介绍类加载器的调用顺序规则。类加载器实际的搜索类的顺序将会被优 先授权方式所影响。这里所讨论的顺序是指类加载器之间的调用顺序,而不是类 加载器亲自去试图加载指定类(或资源)的顺序。 1. 组件类加载器必须是创建 Component 类的初始化加载器。应注意如果组件被 配置为优先授权父加载器(默认配置方式)的话,那么组件类加载器将会在 所有其他加载器之后采取试图加载目标类或资源。 2. 共享库类加载器必须按照组件安装描述文件中声明的顺序搜索类或资源。 3. 组件类加载器必须将所有组件类共享库加载器的集合当作一个单独的父加 载器,也就是说,如果授权给它的父加载器,那么这些共享库类加载器会按 特定的顺序调用。 4. 每个共享库类加载器都必须将 JBI 类加载器作为自己的父加载器。 5. JBI 类加载器必须用平台共享类加载器或系统类加载器作为自己的父加载 器。 6. 平台共享类加载器的父加载器并未在此指定,实际上它是由在平台所指定 的。 JBI 类加载器必须采用优先授权父加载器的方式。 7.3.3.2授权方式(Delegation Style) 7.3.1 节�类和资源的加载方式和顺序�讨论类加载器的授权方式及行为。 如果组件的类加载器的安装描述符指定了 component-class �loader-delegation=�self-first� 则使用 Self-first 授权方式,否则使用 parent-first 方式。同样,如果一 个共享库的安装描述符指定了 class �loader-delegation=�self-first� 121 共享库的类加载器使用 self-first 方式,否则使用 parent-first 方式。 7.3.3.3安 装 和 卸 载 共 享 库 (Installation and Uninstallation of Shared Libraries) 使用管理 InstallationServiceMBean 安装(和卸载)共享库。详见�管理� 一章。 共享库必须在安装使用它的组件之前安装,否则该组件的安装会出错。详 见�管理�一章�共享库安装�和�组件安装�两节。 同样,如果至少有一个组件在使用不是�关闭�的共享库,就无法卸载该共 享库。 7.3.3.4组件的观点(Component Viewpoint) JBI 不发布绑定组件和服务引擎可用来检查和操纵 JBI 类加载模型的 API。 JBI 系统保证组件的 Component 实现使用组件类加载器来构建。组件可隐式地使 用组件类加载器构建其他对象。详见 Java 虚拟机规范第二版[JVM2]5.3 节。 7.3.4 引导类加载器(Bootstrap Class Loader) 引导类加载器由一套类加载器组成,这些类加载器用来加载组件安装过程中 所需的类和资源。另外,引导类加载器必须符合以下几小节定义的规则。 JBI 实现为每个组件提供一个引导类加载器,用来创建组件引导类(在组件 安装描述符中声明)的实例。注意,在组件的扩展生命周期中,JBI 实现可以创 建不止一个这样的实例,但不能同时使用多个实例。 引导类加载器提供组件引导类路径来访问这些类,类路径在组件安装描述符 中的 bootstrap-class-path 声明中制定。引导类加载器按住奥安装描述符里给 定的顺序搜索引导类的路径。 122 JBI 类加载器用来加载 JBI 类。它提供 javax.xml.namespace.QName 类的一 个实现(在 JAX-P1.3 中定义),如果平台类加载器(platform class loader) 或内置类加载器没有提供这个实现的话。 有的执行系统会提供一个平台类加载器(platform class loader)用来加 载共享的平台类。适用于应用服务器等系统,这些系统提供虚拟机内置类加载器 以外的类。 7.3.4.1类加载顺序规则(Class Loading Ordering Rules) 本节指定顺序调用引导类加载器相关的类加载器的规则。实际的查找顺序受 类加载器所用授权方式的影响。该顺序指的是每个类加载器被调用的顺序,它不 同于加载器定义给定的类(或资源)的顺序。 1. 创建组件引导 Bootstrap 类的时候首先使用引导类加载器。 2. 引导类加载器的父加载器是 JBI 类加载器。 3. JBI 类加载器的父加载器一般是平台类加载器,否则使用系统类加载器作为 父加载器。 4. 平台共享类加载器的父加载器是系统类加载器。 JBI 类加载器必须使用 parent-first 授权方式。 7.3.4.2授权形式(Delegation Style) 类加载器授权方式和行为在 7.3.1 节�类和资源加载方式和顺序�讨论。如 果组件安装描述符指定了: Bootstrap-class-loader-delegation=�self-first� 引导类加载器必须使用 self-first 授权方式,否则使用 parent-first 授权 方式。 123 7.4 出错提示(Error Indication) 使用 Java 异常来提示出错信息。所有的 JBI 异常必须基于 javax.jbi.JBIException,从而使组件和管理程序知道错误信息是 JBI 相关的。 JBI 异常的类型有: · 部署异常(DeploymentException)由 DeploymentServiceMBean 抛出给管 理工具,表示部署失败。详见�管理�一章。 · 消息异常(messagingExceptino)由 NMR 抛出,表示当创建、操作、发送或 接收消息交换和规格化消息的时候产生的各种错误。详见�规格化消息路 由�一章。 注意,有的 JBI 管理 bean(MBean)方法规定它们抛出 java.lang.Exception 对象。这是为了避免远程 JMX 客户要求 JBI 异常类匹配版本的问题。
还剩122页未读

继续阅读

下载pdf到电脑,查找使用更方便

pdf的实际排版效果,会与网站的显示效果略有不同!!

需要 15 金币 [ 分享pdf获得金币 ] 1 人已下载

下载pdf

pdf贡献者

gsgsdtc

贡献于2012-02-21

下载需要 15 金币 [金币充值 ]
亲,您也可以通过 分享原创pdf 来获得金币奖励!
下载pdf