JBI规范1.0 (四)
 

2009-11-30 作者:Juset 来源:Juset的blog

 

[6]——管理

JBI系统使用JMX管理。包括提供特定管理接口的JBI组件(可插接绑定组件和引擎)。另外,JBI实现提供特定的JMX管理Beans(MBeans)管理JBI系统提供的基础设施以及JBI组件。再者,JBI实现提供一套Apache Ant任务。

1.1 概述(Overview)

本规范支持的主要管理任务为:

  • JBI的安装和共享库的安装。
  • 安装组件时服务描述信息的部署(对JBI来说是不透明的)。
  • 启动和停止组件(绑定和引擎)和JBI实现组件(如果可用的话)。

所有这些用例假定存在着一个使用JMX来初始化活动的管理工具。JBI实现提供特定的MBeans对管理工具提供管理功能。这些MBeans是:

  • InstallationServiceMBean.管理工具使用此管理bean安装和卸载组件和共享库。
  • InstallerMBean.JBI实现为每个组件的安装提供InstallationServiceMBean。通过组件自己的MBean管理安装过程,包括组件提供的安装配置。
  • DeploymentServiceMBean.管理工具使用此bean为组件部署和解除部署信息,以控制每个部署的运行时状态。
  • LifeCycleMBean.管理工具使用此bean启动和停止JBI实现的模块。(此MBean的使用是依赖于实现的)。
  • ComponentLifeCycleMBean.管理工具使用此bean启动和停止组件。组件可使用组件提供的扩展MBean提供附加的生命周期控制。

另外,组件可发布它们自己的MBean,提供除生命周期和安装扩展以外的特定的组件管理功能。例如,组件可发布一个MBean管理内部日志。

安装和部署要求管理工具发送标准包给合适的MBean。JBI指定了这些包的结构,包括包的标准XML描述符。

1.2 关键概念(Key Concepts)

1.2.1 组件安装(Component Installation)

JBI组件(引擎和绑定)使用本章定义的标准管理机制安装。此外,还定义了为这种组件设计的标准包。目的是保证组件的轻量级,包括安装信息。组件供应商可为分布式生产一个单独的包,而不是基于JBI实现目标的多个变量。通过简化组件获取和管理后台使用户获益。

1.2.2 共享库安装(Shared-library Installation)

Java库可被多个组件共享。使用标准管理机制安装共享库。

1.2.3 部署(Deployment)

许多组件可作为容器,提供(或消费)基于组件包含的信息的服务。例如,一个XSLT引擎包含多种样式表(style sheet),每种样式表提供一种特定的转换服务。

给一个容器组件引进新的信息称为部署(deployment),引入这个名词以便于同组件或共享库的安装予以区分。

1.2.3.1 单元部署(Unit Deployment)

一个发往单个组件的部署包称为服务单元(Service Unit或SU)。服务单元的内容对于JBI来说是不透明的(而不像描述符文件),但对于它即将部署到的组件来说是透明的,同样,对设计时加工生产SU包含的信息来说也是透明的。服务单元包含一个JBI定义的描述符文件,该描述符定义了服务单元生产和消费的静态服务。这有助于创建合成部署。

1.2.3.2 合成部署(Composite Deployment)

JBI系统中创建一个新的服务或消费者应用一般需要多种部署。JBI提供了合成部署的能力支持多种部署,通过部署,几个不同的组件可以组合成服务集合(Service Assembly(SA))。服务集合包括一个合成服务部署描述符,负责服务集合包含的每个服务单元在组件上的部署。注意,服务集合的概念有时也称为“合成服务描述”(CSD:composite service description)。

一个服务集合代表了一个合成服务。由于这层关系,JBI提供了管理功能,用来从整体上对一个服务集合中的每个服务单元的生命周期进行控制。

1.2.3.3 合成服务元数据(Composite Service Metadata)

部署描述符也包括了服务单元和服务提供者之间的服务连接信息,允许服务集合的重组。这些信息分成两类:

  • 服务单元部署后所提供和消费的静态服务的描述。
  • 服务单元和服务集合之间的静态服务互联的描述,以及与服务集合外的服务之间的依赖关系。(如,JBI系统内的其他服务)。

前一类允许使用工具检查静态服务间的依赖关系,并提供一个服务单元且无需分析其内容。组件自身也可能使用这些信息来为服务单元的部署提供配置信息。
后一类允许服务集合的设计者通过声明消费者和提供者之间的新连接,从而改变静态服务消费者和提供者之间的连接。这些连接用来给一个提供者端点重命名,这样当一个消费者请求某个特定的服务端点时,实际上将使用另一个不同的端点。

例如,假设在一个服务集合里有如下元数据:

  • SU1使用端点EP1,
  • EP1连接到EP2。

服务集合成功部署后,如果部署了SU1的组件要发送一个消息交换到EP1,将发送到EP2。

下图是合成服务元数据的示意图。

图22 合成服务示例:单向消息适配器模型

上例基于“JBI系统架构”一章所举的单向消息适配器一例。BC1作为外部服务消费者的代理,BC2作为服务提供者的代理。SE2提供转换服务,SE1编排整个服务,在编排的过程中同时扮演了消费者和提供者两种角色。服务集合负责把SE1连接到SE2和BC2提供的服务上,把BC1连接到SE1提供的单向适配器服务上。

使用合成服务元数据只是JBI提供的连接服务消费者和提供者的几种方法之一。隐式端点选择、消费者动态端点选择及消息交换地址类型详见“规格化消息路由”一章。

1.2.4 部署生命周期(Deployment Life Cycle)

特定的JBI接口为每个组件的部署提供了一个简单的生命周期模型。下图显示了这个模型,同组件的生命周期类似。

图23 部署生命周期状态图

1.2.5 组件生命周期(Component Life Cycle)

特定的JBI管理接口为每个组件管理一个简单的生命周期模型。组件可以添加额外的状态信息扩展该模型。下图显示了基本的生命周期模型

图24 基本组件生命周期状态图

组件的扩展生命周期是在基本生命周期上加上由组件的安装和卸载引入的状态。另外,组件可以使用扩展MBean扩展基本的组件生命周期。例如,一个组件可以使用扩展MBean提供的控制功能为“开始”状态添加一个“暂停”子状态。

1.2.6 类的加载(Class Loading)

JBI实现提供类的加载器,创建组件的引导程序和组件的实现。(详见“框架”一章)。类的加载器通过已声明的类路径访问可用的类。(参见Java语言规范[JLS])(java.lang.ClassLoader)。在组件的扩展生命周期中使用两种类型的类加载器:

  • 引导程序。在组件扩展生命周期中的安装和卸载阶段,组件安装方法使用的类加载器可以访问引导程序类的路径。JBI实现使用类加载器创建组件引导程序(Bootstrap)的一个实例。
  • 执行程序。安装完毕之后,组件进入扩展生命周期中的执行阶段。JBI实现为执行阶段提供的类加载器通过组件声明的类路径访问类和该组件使用到的共享库。JBI实现使用类加载器创建组件(Component)的一个实例。

组件类加载器详见第七章“组件框架”。

1.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执行此规范外的管理任务。关于此机制详见“组件安装”和“组件生命周期”两节。

1.2.8 使用Apahca Ant编写脚本(Use of the Apache Ant for Scripting)

Apache Ant是JBI实现使用的一种标准脚本语言。Ant任务的实现必须用到JMX管理接口。

1.3 包装(Packaging)

JBI为组件的安装和作为“容器”的组件的部署信息定义了标准的包装。安装时将会用到一个描述符,部署时将会用到两种描述符:

  • 服务集合描述符。用来描述一个服务集合的内容。它主要描述了服务集合中的各个服务单元所部署的位置。
  • 服务单元描述符。用来描述一个服务单元提供和消费的服务。

这几种描述符的类型相似,为此引入一个简单的模型。

1.3.1 安装和部署描述符(Installation and Deployment Descriptors)

下图显示了用来创建安装描述符和两种部署描述符的模型,为清晰起见使用RelaxNG缩写方式。

default namespace this = "http://java.sun.com/xml/ns/jbi"
start =
element jbi {
attribute version { xsd:decimal },
( component | shared-library | service-assembly | services)
}
component =
element component {
attribute type { "service-engine" | "binding-component" },
attribute component-class-loader-delegation { "parent-first" | "self-first" }?,
attribute bootstrap-class-loader-delegation { "parent-first" | "self-first" }?,
identification,
element component-class-name { attribute description { text }?, text },
element component-class path { class path },
element bootstrap-class-name { text },
element bootstrap-class path { class path },
shared-library-list*,
element* -this:* { text }*
}
shared-library =
element shared-library {
attribute class-loader-delegation { "parent-first" | "self-first" }?,
attribute version { text }?,
identification,
element shared-library-class path { class path }
}
shared-library-list =
element shared-library {
attribute version { text }?,
text
}
service-assembly =
element service-assembly {
identification,
service-unit*,
connections?,
element* -this:* { text }*
}
service-unit =
element service-unit {
identification,
element target {
element artifacts-zip { text },
element component-name { xsd:NCName }
},
element* -this:* { text }*
}
identification =
element identification {
element name { xsd:NCName },
element description { text },
element* -this:* { text }*
}
class path =
(element path-element { text })+
services =
element services {
attribute binding-component { xsd:boolean },
provides*,
consumes*,
element* -this:* { text }*
}
connections =
element connections {
element connection {
element consumer {
( attribute interface-name { xsd:QName } |
(attribute service-name { xsd:QName }, attribute endpoint-name { text })
)
},
element provider {
attribute service-name { xsd:QName }, attribute endpoint-name { text }
}
}*,
element* -this:* { text }*
}
provides =
element provides {
attribute interface-name { xsd:QName },
attribute service-name {xsd:QName }, attribute endpoint-name { text },
element* -this:* { text }*
}
consumes =
element consumes {
attribute interface-name { xsd:QName },
( attribute service-name {xsd:QName }, attribute endpoint-name { text },
attribute link-type { "standard" | "hard" | "soft" }? )?,
element* -this:* { text }*
}

以下的几个小节详细描述了jbi.xml文件的“jbi”schema所包含产品的用法。

1.3.1.1 使用jbi(Use of jbi)

顶层产品是“jbi”,它是schema生成的所有部署描述符和安装描述符的起始点。

  • Attribute version.一个十进制数值表明所用的描述符的版本信息。对于JBI1.0版本,此数值必须为1.0。
  • type element.表明描述符的类型,必须是以下几种之一:
    • component.表明描述符描述的是一个安装包。
    • service-assembly.表明描述符描述的是一个部署包。
    • shared-library.表明描述符描述的是一个共享库安装包。
    • services.表明描述符是一个服务单元自我描述。

下面给出各种描述符类型的详细用法。

1.3.1.2 使用identification(Use of identification)

identificaion用来为组件、共享库、服务单元和服务集合(以下用都用条目来表示)提供认证信息。identification包含以下数据:

  • name.条目的名称,一个友好的标识符。注意,可对每种类型的条目名前加以其它的限定(如,唯一性)。
  • description. (用一个句子)对条目作较长的描述。
  • extension element(可选).特定的供应商附加的额外的认证信息。JBI不会用到这些信息,但是创建和操纵认证包的工具需要用到附加的认证信息。

1.3.1.3 使用class path(Use of class path)

class path用来为组件和共享库声明一个Java类路径。每个路径的根目录如下:

  • 组件bootstrap-class path和component-class path:在组件安装包的安装目录下。详见“组件框架”一章。
  • 共享库shared-library-class path:在共享库安装包的安装目录下。详见“组件框架”一章。

每个路径使用正斜杠(‘/’)作为文件分隔符。

1.3.1.4 使用shared-library(Use of shared-library)

Shared-library用来描述共享库的安装包。由以下几部分组成:

  • version.表明共享库的版本信息。见组件shared-library-list/shared-library属性。
  • identification.提供共享库的认证信息,其名称必须在JBI系统中所有的安装共享库中是唯一的。
  • shared-library-class path.声明使用共享库的组件的类路径。在shared-library的安装包目录下)。

另外,shared-library有以下属性:

  • class-loader-delegation.如果此可选属性的值为“self-first”,shared-library的类加载器将反转缺省的授权模型(“parent-first”),首先加载类加载器里的类。详见“框架”章中的“类的加载”一节。

1.3.1.5 使用service-assembly(Use of service-assembly)

service-assembly描述服务集合的部署包,它描述了服务集合所包含的服务单元以及这些服务单元将要被部署到的组件信息。

  • identification.合成部署的唯一(在JBI系统中部署的所有服务集合中)标识符。
  • service-units.描述了组件上的单个部署。
  • connections.(可选)包含了服务互联元数据的声明,用于把静态服务消费者和服务提供者联系起来。

1.3.1.6 使用service-unit(Use of service-unit)

service-unit描述service-assembly部署包中的服务组件。

  • identification.service-unit的唯一(部署service-units的目标组件中唯一)名称。
  • target.
    • artifacts-zip.将要部署的部署包中的存档文件名。
    • component-name.将要部署artifacts-zip的组件名。

部署过程详见“部署服务”一节。

1.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()方法访问这些扩展数据。

1.3.1.8 使用connections(Use of connections)

connections用连接元素集声明服务集合的互联元数据。这些数据声明了从消费者提供的数据交换地址到提供者的服务端点之间的对应关系。互联元数据的用法详见6.6.3节。

1.3.1.9 使用connection(Use of connection)

connection声明了从消费者提供的服务地址到提供者的服务端点地址之间的对应关系。所有的组件在使用某项服务时都用到了这个对应关系。consmer子元素声明对应的(连接的)消费者地址的类型。声明有两种形式:

  • service type.通过interface-name属性指定服务类型。所有被赋予给定服务类型的交换都将发送给给定的服务提供者端点。
  • service endpoint.通过service-name属性和endpoint属性指定服务端点。所有被赋予给定服务端点地址的交换都将发送给给定的服务提供者端点。

provider子元素声明消费者连接的服务提供者端点。Provider通过两个属性声明提供者服务端点(provider service endpoint):service-name和endpoint-name。

1.3.1.10 使用services(Use of services)

services声明服务单元提供和消费的静态服务。术语“static”在这里指服务单元部署后提供或消费的服务在设计时期和部署时发期是可知的。binding-component.脱机工具可使用该属性区分服务引擎和绑定组件。它对部署过程无影响。如果组件的类型(在安装描述符中声明的类型)与binding-component属性值不一致,实现会发出一个警告作为部署结果(或状态)的一部分。

1.3.1.11 使用provides(Use of provides)

Provides声明服务单元提供的服务。声明一个服务涉及到以下属性:

  • interface-name.限定名表明所提供服务的类型。
  • service-name和endpoint-name.这对属性声明了部署后服务单元要激活的端点名称。

1.3.1.12 使用consumes(Use of consumes)

Consumes声明服务单元消费的服务。定义一个这样的服务需要使用以下属性:

  • interface-name.限定名表明所消费服务的类型。
    服务单元可指定其消费的服务端点限定名。可选的服务端点名的用法见6.6.3节。如果声明了服务端点名,则可选择此属性。
  • link-type.表明消费者希望通过连接做些什么。此属性的值可能为:
    • standard.默认值。根据标准规格化消息路由规则路由提供的服务端点。
    • hard.提供的服务端点名匹配服务提供者的服务端点名;不允许间接连接。
    • soft.提供的服务端点名不匹配服务提供者的服务端点名,而是匹配一个间接的连接名。

这些值如何影响规格化消息路由详见6.6.3节。

1.3.2 安装包(Installation Packaging)

安装包包括了JBI系统安装一个JBI组件或安装一个组件使用的共享库所需的所有东西,包括一个安装描述符,用来提供JBI安装服务如何处理安装包内容所需的信息。具体的安装过程在“安装服务”中描述。

安装包是一个ZIP存档文件,其内容对JBI系统来说是不透明的,除了安装描述符。安装描述符的命名和存放位置如下:

/META-INF/jbi.xml

安装描述符文件的内容必须与组件安装描述符模型或共享库安装描述符模型一致。

一个安装描述符的示例如下:

<?xml version="1.0" encoding="utf-8"?>
<jbi version="1.0" xmlns="http://java.sun.com/xml/ns/jbi"
xmlns:foo
="http://www.foo.com/ns/bar">
<component type="service-engine">
<identification>
<name>example-engine-1</name>
<description>An example service engine</description>
<foo:TypeInfo part-number="012AB490-578F-114FAA">
BPEL:2.0:XQuery:1.0:XPath:2.0:XPath:1.0
</foo:TypeInfo>
</identification>
<component-class-name description="foo">com.foo.Engine1</component-class-name>
<component-class path>
<path-element>Engine1.jar</path-element>
</component-class path>
<bootstrap-class-name>com.foo.Engine1Bootstrap</bootstrap-class-name>
<bootstrap-class path>
<path-element>Engine1.jar</path-element>
</bootstrap-class path>
<shared-library>slib1</shared-library>
<foo:Configuration version="1.0">
<foo:ThreadPool size="10"/>
<foo:Queue1 size="50"/>
</foo:Configuration>
</component>
</jbi>

上例包含两个“extension”元素,使用一个属于文件元素以外的XML命名空间提供特定的组件信息。JBI实现和组件实现使用这些扩展元素提供额外的特定的组件信息或组件加工信息。

组件供应商使用认证扩展元素提供JBI名称和描述以外的组件认证信息。这些信息允许特定的组件工具识别安装包的类型,并对安装包或安装描述符进行附加的操作。这些信息在组件引导起动时期和执行时期都是可获得的(jbi.xml文件可在安装根目录下的META-INF/jbi.xml找到)。

组件使用组件扩展元素在安装前提供配置信息。这种配置信息和MBean指定的配置信息之间的关系由组件实现来决定。组件通过InstallationContext接口获得这些信息。

1.3.3 服务集合包(Service Assembly Packaging)

服务集合包包含了对JBI来说不透明的部署信息,一个部署描述符,用来提供JBI部署服务如何处理部署包内容所需的信息。具体的安装过程在“部署服务”中描述。

部署包由一个部署描述符和一个或多个服务单元存档文件组成,它们都包含在一个ZIP存档文件中,其文件/目录结构如下:

  • /META-INF/jbi.xml.包含符合部署描述符模型的部署描述符。
  • /{artifacts-file-name.zip}.其中的一个服务单元存档文件名,作为部署描述符目标元素。
  • /{artifacts-file-name-N.zip}.多个服务单元存档文件提供部署描述符jbi.xml中提到的存档文件。

一个部署描述符和部署包存放目录的示例如下。

<?xml version="1.0" encoding="utf-8"?>
<jbi version="1.0" xmlns="http://java.sun.com/xml/ns/jbi">
<service-assembly>
<identification>
<name>example-deployment-1</name>
<description>An example deployment of two service units</description>
</identification>
<service-unit>
<identification>
<name>SU-1</name><description>service unit 1</description>
</identification>
<target>
<artifacts-zip>su1-artifacts.zip</artifacts-zip>
<component-name>bpel-engine-1</component-name>
</target>
</service-unit>
<service-unit>
<identification>
<name>SU-2</name><description>service unit 2</description>
</identification>
<target>
<artifacts-zip>su2-artifacts.zip</artifacts-zip>
<component-name>xslt-engine-1</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>

/META-INF/jbi.xml

/su1-artifacts.zip

/su2-artifacts.zip

部署描述符引用了部署包中的两个独立文件。这两个文件加上部署描述符组成了俄一个单独的ZIP文件,如图20所示。

1.3.4 服务单元包(Service Unit Packaging)

服务单元存档文件必须包含一个单独的JBI定义的描述符文件:

  • /META-INF/jbi.xml.包含符合服务模型的服务单元描述符。

服务单元描述符提供部署服务单元到目标组件而静态的提供或消费的服务的信息。

1.4 服务安装(Installation Service)

安装服务允许管理工具从JBI系统中安装和卸载组件和共享库。

1.4.1 共享库安装(Shared Library Installation)

共享库的安装包可以使用InstallationServiceMBean安装和卸载:

  • 安装。管理工具调用安装服务MBean的installSharedLibrary()方法安装共享库,提供安装包存放的URL。安装包必须包含一个共享库安装描述符。
  • 卸载。管理工具调用安装服务MBean的uninstallSharedLibrary()方法卸载共享库,说明将要卸载的共享库名。要卸载的共享库名必须和安装时安装描述符提供的库名一致。

1.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相关的组件是否已安装。
  • 卸载组件。管理工具可调用uninstall()方法卸载InstallerMBean相关的组件。

1.4.2.1 安装过程(Installation Process)

安装过程涉及到同管理工具的以下两种交互:

  • 使用InstallerServiceMBean加载installer,为组件创建一个InstallerMBean。
  • 使用上步创建的InstallerMBean运行installer。

管理工具还可能与一个安装扩展MBean进行交互。

以下几小节详细阐述了安装的具体步骤。

1.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),在安装描述符中给出。
  • 安装扩展数据。一个包含了安装描述符中的安装扩展信息的DOM片段。如果描述符中没有安装扩展信息,此DOM片段为null。

2. 准备引导类加载器。JBI实现创建一个类加载器,可以访问安装包描述符中声明的引导类路径。类加载器的描述详见第七章“组件框架”。

3. 初始化Installer。使用上述类加载器,JBI实现创建一个安装描述符中声明的引导类实例。这个实例调用init()方法初始化引导程序,并把它传给第1步准备好的安装环境。此时 ,组件提供的引导程序可以使用组件环境中的JMX服务器注册一个安装扩展MBean。

4. 创建Installer MBean。引导程序调用init()方法后,JBI实现为组件创建并注册一个InstallerMBean。注意,InstallerMBean需要到引导加载器对象和安装环境的引用来完成安装。

1.4.2.1.2 自定义安装(Customized Installation)

加载installer之后,管理工具从InstallerMBean接收一个JMX对象名。管理工具使用InstallerMBean的getInstallerConfigurationMBean()方法检查InstallerConfigurationMBean是否存在。如果不存在,需要在管理工具运行installer之前使用InstallerConfigurationMBean进行自定义安装。

1.4.2.1.3 运行Installer(Run Installer)

加载installer之后,管理工具从InstallerMBean接收一个JMX对象名。管理工具调用InstallerMBean的install()方法完成安装。JBI实现执行以下步骤以完成安装。

1. 调用引导对象的onInstall()方法。

2. 调用引导对象的cleanUp()方法。此时引导程序对任何先前注册过的MBean撤销注册。

成功调用install()将返回ComponentLifeCycleMBean的JMX 对象名。ComponentLifeCycleMBean用来控制组件的运行状态。见“组件生命周期”。

1.4.3 组件卸载(Component Uninstallation)

使用InstallerMBean卸载组件,卸载过程是安装的逆过程。注意,卸载时使用的引导类实例并不保证一定是组件安装过程中使用的那个。

注意,如果引导程序的init()方法注册了一个扩展MBean,引导程序的cleanUp()方法就会撤销注册。

1.5 组件生命周期(Component Life Cycle)

每个组件的生命周期都:

  • 从使用InstallationServiceMBean安装组件开始。组件的状态为“已安装”。组件的所有执行状态都可以看作是“已安装”状态的子状态。
  • 通过ComponentLifeCycleMBean控制,对于自定义生命周期子状态,还可能会用到一个生命周期扩展MBean。
  • 通过组件使用ComponentLifeCycle SPI实现。详见“框架”一章。
  • JBI实现提供ComponentLifeCycleMBean,它与组件SPI实现共同控制组件生命周期中的各个状态。

每个已安装的组件都有一个最小生命周期,如图所示。

图25 组件生命周期状态图

最小生命周期使用两种JBI MBean:InstallerMBean,控制是否安装组件到JBI系统。(如,已安装状态);ComponentLifeCycleMBean,控制更常规的组件开始/停止生命周期。组件可以通过一个生命周期扩展MBean来扩展常规生命周期,扩展MBean提供额外的生命周期状态。图26在标准“开始”状态上加了一个“暂停”子状态。通过使用扩展MBean提供的“暂停”控制访问这个附加的子状态。

图26 扩展组件生命周期状态图

管理工具通过ComponentLifeCycleMBean和生命周期扩展MBean改变组件的运行状态。组件ComponentLifeCycle接口的实现提供执行状态转换的具体逻辑。JBI实现负责:

  • 维持组件的基本执行状态。
  • 将ComponentLifeCycle方法的调用进行排序以保证基本执行状态的合法转换。例如,如果管理工具调用start()MBean控制一个处于关闭状态的组件,实现必须按照顺序调用ComponentLifeCycle的init()和start()方法。组件生命周期方法详见“框架”一章。

注意,如果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()方法或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。

1.6 服务部署(Deployment Service)

部署服务允许管理工具把服务集合部署和解除部署到JBI系统,或从JBI系统中把服务集合部署和解除到其他地方,并控制这些服务集合的运行状态。

部署由服务集合组成,详见“服务集合包装”一节。管理工具调用DeploymentServiceMBean的deploy()方法请求一个服务集合的部署,为服务集合包的资源传递一个URL。服务集合包必须符合“服务集合包装”一节中的要求,否则无法部署服务集合中的任何服务单元(抛出java.lang.Exception异常)。

注意,一个“复制”的服务单元指的是:

  • 和先前部署到组件中的服务单元有相同的名字。
  • 和先前部署到组件中的服务单元有相同的内容(服务单元具有同样的长度和同样的二进制数据)。

JBI实现必须能够发现这些复制品。部署一个和先前已部署过的服务单元同名的非复制服务单元会出错,而重部署一个复制的服务单元不会出错。

当“部署”方法接收到一个有效的部署包时,JBI实现做出以下处理步骤:

1. 确认部署包,确保部署描述符符合6.3.3节的要求。同时确保部署包中包含所有的服务单元信息,所有指定的目标组件都已安装到JBI系统中。

2. 对<service-assembly>部署描述符中的每个<service-unit>:

  • 解压服务单元描述信息文件到文件存储空间。(如果同一个部署描述符中服务单元被部署到多个组件上,服务单元必须被复制,这样一个组件对部署内容做出改动不会影响到其他的组件上的部署信息)。
  • 把指定的服务单元部署到指定的组件。详见“服务单元部署过程”一节。

如果步骤2的任何一次重复不能把指定的服务单元部署到指定的组件过程中,实现必须继续部署服务集合中剩余的服务单元。如果服务集合中的所有服务单元都没有部署成功,抛出一个部署失败的异常。如果至少有一个服务单元部署成功,调用DeploymentServiceMBean的deploy()方法,使用状态返回的字符串报错。该字符串的格式在6.9节中规定。

如果服务单元的部署是一个复制,部署被跳过而不是作为一个部署错误。这样,服务集合会重新部署而不会打扰现有的部署。

DeploymentServiceMBean还用来控制服务集合的生命周期,见6.8节。

1.6.1 服务单元部署过程(Service Unit Deployment Processing)

本节详述了如何部署一个服务单元。JBI实现保存服务单元信息。对每一个服务单元,JBI实现对非复制的服务单元部署执行以下操作。执行的顺序同服务单元在服务集合描述符中声明的顺序一致。

1. 查找目标组件的ServiceUnitManager接口。注意,组件(而不是JBI实现)提供该接口,JBI实现调用组件的Component.getServiceUnitManager()方法查找该接口。

2. 实现为每个服务单元分配资源,包括服务单元部署的文件存储空间。

3. 实现解压(“释放”)服务单元的内容到为其分配的存储空间根目录下。

4. 实现使用ServiceUnitManager接口的deploy()方法,提供部署描述符中声明的服务单元名以及服务单元描述信息的根路径名,从而部署服务单元描述信息到组件上。

此时,服务单元部署已完成,并开始生命周期管理。详见“6.7”节。第一次安装,服务单元(及其所在的服务集合)处于“关闭”状态。

1.6.2 服务集合撤销部署过程(Service Assembly Undeployment Processing)

服务集合在可以撤销部署之前必须处于关闭状态。服务集合使用DeploymentServiceMBean的undeploy()方法撤销部署,undeploy()使用将要撤销部署的服务集合名作为参数。对指定的服务集合中的每个服务单元,JBI实现执行以下操作。操作的顺序与服务集合描述符中服务单元声明的顺序正好相反。

1. 查找目标组件的ServiceUnitManager接口。注意,组件(而不是JBI实现)提供该接口,JBI实现调用组件的Component接口实现的getServiceUnitManager()方法查找该接口。

2. 实现使用ServiceUnitManager接口的undeploy()方法,提供部署描述符中声明的服务单元名以及服务单元描述信息的根路径名,从组件上撤销服务单元的部署。

3. 实现释放分配给服务单元部署的资源,包括服务单元存放的根目录下的存储空间。

1.6.3 连接元数据处理(Connection Metadata Handling)

服务集合包含连接元数据:描述消费者提供的服务地址到服务提供者端点地址之间的映射的数据。映射影响NMR如何路由消费者和提供者之间的消息交换。(详见“规格化消息路由”一章)。连接元数据可通过操纵现存的服务单元合成新的服务集合,还可用在管理方面。

JBI实现使用服务集合部署描述中的连接元数据,创建服务连接——执行规格化消息路由时JBI实现必须用到的映射。(其过程详见“规格化消息路由”一章)
服务连接的逻辑结构包含两个地址:

  • 消费者地址。一个由服务消费者提供的地址,有两种形式:
    • 服务类型名。消费者通过接口名指定希望获得的服务类型。
    • 服务端点名。消费者通过限定名指定希望获得的服务端点。
  • 提供者端点地址。发送消息交换给消费者地址的实际提供者的地址。

1.6.3.1 链接类型(Link Types)

规格化消息路把消息交换从发起的消费者处发送至一个提供者。有时消费者可能希望管理服务连接如何路由它发起的消息交换。用术语“提供者链接类型”来描述这种情况。有三种可能的提供者链接类型:

  • 标准链接。NMR执行正常路由,包括使用服务连接。
  • 硬链接。消费者一般直接指定提供者的端点,路由不受服务连接的影响。换句话说,消费者要求给定的端点地址必须是一个内部端点。
  • 软链接。消费者使用一个间接地址指定提供者端点。此时消费者提供一个“假”(并不存在的)端点。这种类型的链接是消费者的一个声明:给定的地址必须使用一个服务连接来解析。如果该端点是一个内部端点的话就会引发错误。

1.6.3.2 服务单元和规格化消息路由(Service Units and Normalized Message Routing)

服务单元包含它所提供和消费的静态服务的元数据。这些数据主要用来合成(或分解)服务集合。服务单元为所消费的服务声明了一个特定的属性,该属性影响JBI实现如何处理链接。这个属性就是消费者元素中的link-type,用来指定一个服务单元的消费者服务链接类型。各种链接类型在6.6.3.1节定义。

JBI实现在部署一个服务单元时必须读取该服务单元部署描述符并收集所有的链接类型声明。这些将影响到服务单元部署的组件发起的消息交换如何进行规格化消息路由(详见“规格化消息路由”一章)。JBI实现在服务集合启动之前必须收集部署相关的所有服务连接和链接类型信息并使其生效。在服务集合停止或关闭之后JBI实现挂起该服务集合中所有的服务连接。

1.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()把一个服务单元恢复到关闭状态。

无论哪种状态恢复,实现在调用其它生命周期的方法之前首先调用init()。

1.8 服务集合生命周期(Service Assembly Life Cycle)

每个服务集合都有一个生命周期,同服务集合中的服务单元的生命周期类似。图30描述了这样一个状态图。

图30 服务集合生命周期状态图

每个服务集合通过管理工具使用DeploymentServiceMBean管理其生命周期:

  • start(serviceAssemblyName)方法将启动服务集合中当前状态不是启动(Started)的每个服务单元。如果服务单元处于关闭(Shutdown)状态,实现首先对这些服务单元调用init()。
  • stop(serviceAssemblyName)方法将停止服务集合中当前处于启动(Started)状态的每个服务单元。
  • shutDown(serviceAssemblyName)方法将关闭服务集合中当前未关闭的服务单元。对所有处于启动状态的服务单元,实现在试图关闭这些服务单元之前首先停止它们。

当处理上述管理命令时,如果任何试图改变服务单元的运行状态失败了,错误必须用返回状态/结果字符串报错(其格式详见6.9节)。

注意,每个服务单元的运行状态由ServiceUnitManager的生命周期管理来控制。访问每个组件的ServiceUnitManager见6.6.1节。

1.9 MBean状态和结果字符串(MBean Status and Result Strings)

很多JBI管理bean的方法要求使用一个字符串状态/结果代码,用来传达执行特定的管理任务后的结果,包括出错信息。本节定义这种字符创的格式。使用符合以下模型的序列化XML文件,作为Java字符串传递,传达调用JBI实现MBean的某些管理方法后的状态和结果。

这种方法有许多优点。使用XML,避免了在分布式环境尤其是使用JMX时的同步类定义问题。另外,XML易操作,允许管理工具充分利用结果、出错信息显示、日志结果等信息。

组件使用的模型结构如下:

default namespace = "http://java.sun.com/xml/ns/jbi/management-message"
start =
element jbi-task {
attribute version { xsd:decimal },
jbi-task-result
}
jbi-task-result =
element jbi-task-result {
frmwk-task-result,
component-task-result*
}
frmwk-task-result =
element frmwk-task-result {
frmwk-task-result-details,
element is-cause-framework { "YES" | "NO"}?
}
component-task-result =
element component-task-result {
element component-name { xsd:NCName },
component-task-result-details
}
frmwk-task-result-details =
element frmwk-task-result-details {
task-result-details,
element locale { text }
}
component-task-result-details =
element component-task-result-details {
task-result-details
}
task-result-details =
element task-result-details {
element task-id { text },
element task-result { "SUCCESS" | "FAILED" },
element message-type { "ERROR" | "WARNING" | "INFO" }?,
element task-status-msg { msg-loc-info }*,
exception-info*
}
msg-loc-info =
element msg-loc-info {
element loc-token { text },
element loc-message { text },
element loc-param { text }*
}
exception-info =
element exception-info {
element nesting-level { xsd:integer },
msg-loc-info,
element stack-trace { text }
}
  • jbi-task与文件命名空间一起的文件元素,标识本文件为一个JBI管理任务结果/状态报告。
  • jbi-task-result报告实现执行任务的结果,以及执行任务的组件部分的结果。后者只在特定的情况下出现(任务涉及到与一个组件交互,任务进行到交互开始的那一点)。
  • frmwk-task-result报告实现执行任务的结果。包括一个可选的元素,is-cause-framework,当JBI实现造成任务不能执行时,该元素被设置为“Yes”。
  • 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。
    • loc-token用来寻找消息的本地化信息的消息密钥。
    • loc-message默认的消息。所有的消息都必须使用java.text.MessageFormat格式定义消息以及消息中参数的位置。
    • loc-param消息的零个或多个参数。
  • exception-info报告异常,包括以下条目:
    • nesting-level用整型数值表明该异常在一个嵌套的异常中所处的层次。
    • msg-loc-info报告异常消息值。
    • stack-trace报告抛出异常的点的栈追踪。

下图显示了一个部署错误的例子。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<jbi-task version = "1.0"
xmlns 
= "http://java.sun.com/xml/ns/jbi/management-message">
<jbi-task-result>
<frmwk-task-result>
<frmwk-task-result-details>
<task-result-details>
<task-id>deploy</task-id>
<task-result>FAILED</task-result>
<message-type>ERROR</message-type>
<exception-info>
<nesting-level>1</nesting-level>
<msg-loc-info>
<loc-token>JBI1009</loc-token>
<loc-message>Unable to deploy {1}. Missing {2} section in jbi.xml
</loc-message>
<loc-param>file://d/jbi/samples/1/sampleAU.jar</loc-param>
<loc-param>service-unit</loc-param>
</msg-loc-info>
<stack-trace>....</stack-trace>
</exception-info>
<locale>en</locale>
</task-result-details>
</frmwk-task-result-details>
<is-cause-framework>YES</is-cause-framework>
</frmwk-task-result>
</jbi-task-result>
</jbi-task>
Listing 22 Example

本例中,错误是由JBI实现(框架)发现的一个畸形的部署描述符而引起的。

组件提供状态/结果字符串作为XML字符串,符合component-task-result-details类型。例如,ServiceUnitManager.deploy()方法返回这样一个状态/结果字符串。JBI实现把组件提供的状态/结果字符串合成为一个整体的状态/结果文件。

1.10 Ant脚本支持(Ant Script Support)

略。

火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。

资源网站: UML软件工程组织