级别: 中级 Mouli Narayanan (mouli_narayanan@thbs.com), Architect and Strategist, Torry Harris Business Solutions Srivathsa T.V. (srivathsa_vijay@thbs.com), Technical Lead, Torry Harris Business Solutions
2003 年 9 月 01 日 更新 2003 年 9 月 12 日 Web服务作为一种能够快速集成应用的技术,如果与异步传输进行组合,就将为构建企业级应用提供所需的可靠性。在本文中,我们尝试用两种设计方法来部署和访问异步web服务(通过使用 Apache Axis)。在第一种方法中,用WebSphere MQ support pac、MA0R来提供MQ传输(利用WSDL的可扩展性),而在第二种方法中,将自定义JMS发送者和侦听者传输处理器插入Axis可扩展框架。第一种方法使Web服务的开发和部署更加容易,而第二种方法提供了插入我们自己的传输处理器的灵活性。
引言
SOAP最初是作为一种通过 HTTP(Internet)进行同步RPC调用的简单方式出现的,但是后来它发展成可以通过多种协议进行同步和异步RPC调用。
在过去的几年中,企业级应用使用异步传输已经成为了一种趋势。从可靠性处理的角度来看(也就是重发、超时和复制检测),与异步传输分离能够使应用程序具有更好的可伸缩性,并且简化了应用程序中的处理逻辑。因为Web服务是一种快速集成应用程序的技术,所以将现有的企业应用公开为Web服务(服务提供者)已经成为了一种趋势。这样的服务的客户(服务消费者)可以访问这些具有多层可靠性的服务,取决于访问服务所用的协议。
当通过HTTP访问这些服务时,在传输层可以得到有限的保证,并且客户端应用有责任检查超时、重发和复制检测。对于访问响应时间有限的短期业务流程的低容量应用而言,这是一个低成本的解决方案。因为应用必须处理的事情不只是业务逻辑,所以在多应用中传输的低成本被重复实现的复杂性所抵消。
不过,当通过可靠异步传输访问服务提供者时,服务消费者应用可以减少它的某些责任,因为面向消息的中间件(Message Oriented Middleware,MOM)代表该应用处理这些问题,因而应用可以更多地关注业务逻辑。在将遗留MQ应用(支持 fire和forget模型)公开为服务提供者时尤其如此。
基于异步传输的SOAP是一种应用模式,它由于种种原因而赢得了大量的关注,比如长期的业务流程、服务提供者和服务消费者的松散耦合(从服务可用性和组件边界点的分离的角度看)、增强的服务可伸缩性使异步模型执行路径的长度缩短。可以通过两种方式使Web服务的可靠性提高,第一种方式是在SOAP消息本身使用确认(例如,ebXML),另一种方式是在比HTTP更可靠的传输中携带SOAP有效载荷。本文档的重点是,展示为通过异步协议(如Series)携带SOAP有效载荷设计的可选方案,不过,相同的理论可以应用到其他MOM厂商的产品。
本文档假定您基本理解Web服务堆栈和WebSphere
MQ。
有多种设计方法可以用来为基于异步传输的SOAP应用模式提供解决方案。
- 第一种方法是使用WSDL的可扩展性来加入同步绑定。
- 第二种方法是使用框架,它使得可以将传输处理器插入服务消费者和服务生产者的路径。
- 第三种方法是使用自定义适配器,它可以将协议从HTTP转换为MQ/JMS。
使用第一种方法,绑定应该是WebSphere MQ或JMS吗?没有工业标准方式来扩展WSDL绑定,
而不同的厂商正在通过把本地传输协议绑定到传输协议中来实现WSDL扩展,不过,与此同时,基于JMS的绑定应该是一种可行的方式,而且Apache的WSIF接近于为这样的绑定指定XMLSchema。参见参考资料部份可以获得更多关于WSIF的更多信息。但是,更困难的部分在于工具(java2wsdl和wsdl2java)的可用性,这两种工具可以用于生成处理异步传输的stub和skeleton,而在当前的WSIF中,这两种工具是不可用的。
第二种方法的例子是Apache的Axis框架(framework),它允许在客户端和服务器锻连接处理器。第三种方法的例子将在本文中提及(参见参考资料)。
在本文中,我们已经比较深入地探讨实现问题,并且分析了前面提出的方案1和2。
此外,WSDL规范支持一个端点可以指定的四种传输基本方式:
在本文中,我们的兴趣在于评估单向和请求/应答通信模式的设计实现。要求/响应、通知和pub/sub模型是超出了本文讨论范围的传输方式。体系结构中与安全性相关的细节将在下一篇文章中进行讨论。
体系结构
下面展示了Axis所用的通过SOAP over
HTTP建立调用服务的方式。Java2Wsdl工具生成带有HTTP绑定的WSDL。Wsdl2Java工具生成客户端应用所需的stub和服务器端所用的skeleton。
当客户端实现进行RPC调用时,stub会将请求编组并使参数序列化。与此操作有关的其他问题是Java编程语言类型的编码方式和
XML类型的编码方式之间的转换。WSDL将成为服务的组件接口。这一部分将分析上述三种设计方案中头两种。
方案
MA0R使用的是这种体系结构。support pac提供了自己的Java2Wsdl和Wsdl2Java工具的实现,这两种工具生成和处理带有MQ本地绑定的WSDL。它们已经定义了URI映射来完成这一任务。下图对此进行了展示。
SupportPac为Apache Axis Web Services框架提供插件传输,并且允许在客户端和在这些环境的某一种中编写的服务之间进行基于WebSphere MQ传输协议的互操作性。
客户端程序通常调用适当的Axis框架。stub把该调用编组成SOAP请求消息,和SOAP/HTTP完全一样。
当stub标识URI
[wmq:xxx]时,它调用MA0R SupportPac中所提供的WebSphere MQ传输发送者代码。然后将其传送到也是由MA0R提供的侦听者。此侦听者阅读传入的SOAP请求,然后将其交给适当的Web服务体系结构。该体系结构调用服务,方式和为基于HTTP传输协议传入的消息所做的完全一样。
它然后将响应编组成SOAP响应消息,并且把它送回到MA0R侦听者。该侦听者将通过WebSphere MQ传输的消息送回到MA0R发送者,MA0R发送者再将它传送到客户端Web服务体系结构。客户端体系结构解析响应SOAP消息,然后将结果送回到客户端应用。
Axis框架是最新 SOAP规范(SOAP
1.2)基于Java的开放源代码实现,而带有附加规范的SOAP来自Apache社团。下面是此Axis框架的关键特征:
- 灵活的消息传递框架:它提供了灵活的消息传递框架,包括处理器、链、序列化器和反序列化器。处理器是处理请求、响应和缺省流的对象。处理器可以组成链,而这些处理器的次序可以使用灵活的部署描述符进行设定。
- 灵活的传输框架:Axis提供了一种传输框架,可以用来帮助用户创建他们自己的可插入传输发送者和传输侦听者。
- 数据编码支持:Axis使得可以自动序列化各种各样遵循XML Schema规范的数据类型,并且提供了一个工具,可以用来创建自定义的序列化器和反序列化器。
- 附加特征:Axis 1.2提供了对WSDL以及记录、错误和缺省处理机制的完全支持。
这个方案利用Axis框架Flexible Transport(灵活传输)的特征,而不利用WSDL扩展。下图展示了该方案的体系结构。
在这种情况下,没有stub/skeleton生成。客户端将会把传输处理器设置为在应用中进行调用,并且使用SOAP
API调用Web服务。
把指定传输处理器的部署描述符准备好,并且将其部署到客户端的Axis引擎上。在运行时,Axis框架会载入传输处理器。
可以用JMS传输处理器来发送和接收基于JMS的SOAP消息。
上面的框架可以通过以下步骤进行演示:
- SOAP客户端构造调用对象,设置位置、服务、方法名和传输机制,并且调用Axis客户端。
- Axis客户端检查部署描述符中的传输对象,并且载入为JMS传输开发的传输处理器。
- JMS SOAP处理器从客户端接收SOAP请求,并且把请求放在请求队列中。
- 当消息到达请求队列时,When the message arrives at request queue, the JMS SOAP侦听者提取 Listener takes the JMS请求,然后把它转换到SOAP请求,并且调用Axis服务器引擎。
- Axis服务器引擎调用相应的Web服务,并且将响应返回到JMS侦听者,而JMS侦听者把应答放在响应队列中。
- JMS SOAP处理器在应答消息到达时得到通知。它然后将应答转换成SOAP消息,并将其返回到客户端。
分析
对于特定的问题描述,这一部分比较两种解决方案(根据前一部分确定的两种可选方案而提出的)的部署、客户端实现、执行和操作的难易程度。注意到消息传递是持久化的而最优化客户端代码可以获得更好的性能(指出了可以应用这些的地方),这一点很重要。使用非持久化WebSphere MQ比使用HTTP更昂贵,因为它没有提高可靠性特征。
问题描述
Data Transformation(数据转换)是用在应用程序集成区的常见服务。作为一种需要公开的典型服务,我们利用了Cash Trade(现金交易)事务。传入消息以XML的形式包含Cash Trade详细情况,而Cash Trade消息的字段中的转换是基于满足接收应用指定的Schema的XSL文件进行的。这包括对消息的结构和语义两方面进行更改。消息的大小大约是35K字节。
为了模拟该问题,我们创建了一个Web服务,其中,LOB AD可以通过注册XSL来建立转换,而随后就能够通过调用带有有效载荷的转换来利用该转换。目前,这是一个次优的版本,其中,会对每个请求建立转换并调用转换。在产品质量代码中,setup()和invoke()将是两个不同的调用,带有保留在服务器端的状态信息。
下面是“SimpleTransformation.java”的实现,它根据给定的XSL来进行从源XML文件到目的XML文件的转换。不过,转换本身超出了本文所讨论的范围。
清单
1. SimpleTransformation
public class SimpleTransformation {
public int setupTransformation(byte[] b1, byte[] b2) throws Exception,
SAXException,TransformerConfigurationException{
// Instantiate a TransformerFactory.
tFactory = TransformerFactory.newInstance();
// convert the incoming byte array to InputStreams
.....
.....
InputSource isource = new InputSource(is2);
Source source = new SAXSource( isource );
Result result = new SAXResult( serializer.asContentHandler());
//transform
transformer = tHandler.getTransformer();
transformer.transform( source , result);
return 1;
}
}
|
试验设备
这个原型建立在Windows 2000平台上,处理器为PIII,内存为256MB。客户端和服务器运行在同一台机器上,这样网络时间就不会对分析造成影响。
部署
运行“deployWMQService.bat”(Windows)(在为服务存放源代码的目录下的SupportPac文件中),然后部署服务。完成部署需要进行一些操作。下面是在Windows NT上由deployWMQService批处理文件执行的步骤。
- 编译源代码,并且把类放到类子目录javac SimpleTransformation.java中
- 使用SupportPac中提供的“Java2WSDL”生成适当的WSDL。将该WSDL文件命名为“javaDemos.server.SimpleTransformation_Wmq.wsdl”。所生成的WSDL文件将包含位置,比如“wmq:SOAP.javaDemos.server.SimpleTransformation@MQSOAP.DEMO.QM?connectQueueManager=MQSOAP.DEMO.QM”
- 准备部署描述符文件并且部署到执行目录中。下面示所生成的WSDD文件:
- SimpleTransformation_deploy.wsdd
- SimpleTransformation_undeploy.wsdd
- server-config.wsdd
- 从生成的WSDL文件中生成适当的Java代理。SupportPac给stub生成器提供自定义WSDL,stub生成器名为
“com.ibm.mq.ma0r.tools.RunWSDL2Java”,它可以理解URI“wmq:xxx”。从stub生成器生成的WSD和代理将有适当的URI,可以用于调用服务。例如:“wmq:SOAP.javaDemos.server.SimpleTransformation@MQSOAP.DEMO.QM?connectQueueManager=MQSOAP.DEMO.QM”
- 将该Java代理编译到类子目录中
- 准备WMQ队列,以存放对服务的请求。请注意:在运行此脚本之前必须创建队列管理器(queue
manager)
- 准备文件,以启动将处理此队列的侦听者
- 准备WMQ定义,它将允许自动触发侦听者流程。例如:
- WMQ流程:SOAP.javaDemos.server.SimpleTransformation
- WMQ Trigger Initiation
Queue:SOAP.INITQ
- 将为SimpleTransformation生成的WSDD文件部署到Axis引擎中[使用java org.apache.Axis.utils.Admin服务器]
实现客户端
在实现客户端之前,必须编译生成的WSDL文件,以生成客户端和部署描述符所需的stub。用于调用Web服务的样本客户端代码如下所示:
清单
2.
客户端代码片断
public class WMQClient
{
public static void main( String[] args ) throws IOException, javax.xml.rpc.ServiceException
{
// Must register WMQ transport extensions before doing SOAP/MQ
com.ibm.mq.ma0r.usage.Util.registerExtensions();
Options opts = new Options( args );
int result=0;
byte[] b1;
byte[] b2;
try {
// Use the locator to get a handle to the service on a specific WSDL Port
SimpleTransformationService locator = new SimpleTransformationServiceLocator ();
SimpleTransformation service= locator.getJavaDemosServerSimpleTransformation_Wmq();
/* Convert the data in .xml and .xsl file to byte array to be passed
*to the web service
*/
.....
.....
result = service.setupTransformation( b1,b2 );
} catch ( Exception e ){
System.out.println("\\n>>> EXCEPTION WHILE RUNNING ProxyClient DEMO <<<\\n");
e.printStackTrace();
System.exit( 2 );
}
}
}
|
注意:The 在调用Web服务之前,生成的stub使用base64编码对SOAP有效载荷进行编码。如果再没有编码之前就发送SOAP有效载荷,将会对性能造成很大的影响。
执行
在执行客户端之前,必须完成以下任务:
- 创建队列管理器。创建发送和接收队列,以用于发送和接收SOAP消息。
- 启动SupportPac中提供的侦听者程序,而如果请求传入时需要自动启动侦听者程序,则启动触发器监视器。这也将需要定义流程。
现在,可以执行客户端程序以访问“SimpleTransformation”Web服务。
优点和缺点
|
优点
|
缺点
|
- 支持Microsoft .NET Web服务框架
- 由于使用了WSDL,因此可以更容易地实现客户端
- 可以使用工具来生成stub/skeleton(WSDL2JAva和Java2WSDL)
- 更易于部署
|
- 不支持带附件的SOAP
- 不支持WMQ客户端连接
- 对WMQ详细情况的控制非常有限
- Axis客户端不能调用使用DOC样式SOAP的.NET服务器
- 不支持多线程侦听者
- 对类似于到期(expiry)这样的WMQ详细情况的控制非常有限
- 不能确定Supportpac是否存在于产品中
|
方案
部署
要部署上面的服务。就必须在服务器上完成以下任务:
1. 必须将所需的类放入CLASSPATH环境变量中
2. 编译Web服务源文件
3. 启动Simple Axis Server(也可以使用OR Tomcat)
4. 为部署SimpleTransformation服务准备WSDD文件。请注意:在这种情况下,没有WSDD文件生成。必须手工准备WSDD文件。如下所示:
清单
3.
用于服务提供者的WSDD
<deployment xmlns="http://xml.apache.org/Axis/wsdd/"
xmlns:java="http://xml.apache.org/Axis/wsdd/providers/java"
name="TransformationService">
<service name="SimpleTransformation" provider="java:RPC">
<parameter value="javaDemos.server.SimpleTransformation" name="className"/>
<parameter value="*" name="allowedMethods"/>
</service>
</deployment>
|
5. 将“SimpleTransformation”的WSDD文件部署到Axis引擎java org.apache.Axis.utils.Admin server SimpleTransformation.wsdd中[使用java org.apache.Axis.utils.Admin服务器]
6. 现在,我们需要在客户端上配置JMS MQSeries Transport。客户端WSDD文件如下所示:
清单
4.
用于消费者的WSDD
<deployment xmlns="http://xml.apache.org/Axis/wsdd/"
xmlns:java="http://xml.apache.org/Axis/wsdd/providers/java">
<handler name="JMSMQSender" type="java:javaDemos.jms.JMSSOAPSender"/>
<transport name="JMSTransport" pivot="JMSMQSender"/>
</deployment>
|
7. 要部署客户端WSDD,请执行以下命令:
java org.apache.Axis.utils.Admin client jmsclient-deploy.wsdd
可选的客户端指示部署信息只用于客户端。您现在所做的是部署您的体系结构。
实现客户端
用于调用Web服务的客户端如下所示。调用“call.addParameter”的就是一个重要的客户端。它在发送请求之前编码SOAP有效载荷。
“base64Binary”表示Base64编码的任意二进制数据。对于base64Binary数据,使用RFC
2045]的6.8节定义的Base64 Content-Transfer-Encoding编码整个二进制流(stream)。
不编码SOAP有效载荷可能会在响应时间上对性能造成严重的影响。
清单
5. AXIS客户端代码片断
public static void main(String args[]) {
// Method Name to invoke for the Web Service
String methodName = "setupTransformation";
/* Read the files .xml and .xsl and convert them into byte
* arrays to be sent to the Web service
*/
...
...
JMSTransport transport = new JMSTransport(connectorMap, cfMap);
// Create the Service call
Service service = new Service();
Call call = (Call) service.createCall();
QName qname= new QName("SimpleTransformation", methodName);
call.setOperationName(qname);
call.addParameter(new javax.xml.namespace.QName("", "byte1"),
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema", "base64Binary"),
byte[].class, javax.xml.rpc.ParameterMode.IN);
call.addParameter(new javax.xml.namespace.QName("", "byte2"),
new javax.xml.namespace.QName(
"http://www.w3.org/2001/XMLSchema", "base64Binary"),
byte[].class, javax.xml.rpc.ParameterMode.IN);
call.setTransport(transport);
call.setReturnType(XMLType.XSD_INT);
result = call.invoke(new Object[] { b1, b2 });
...
...
}
|
执行
在执行客户端程序以访问框架之前,必须完成以下任务:1.
创建MQ对象,比如队列管理器和队列。2. 创建JMS管理的对象,比如队列连接工厂和队列。对于WebSphere
MQ,可以用JMSAdmin创建JMS管理的对象。使用MQSeries安装目录中的“JMSAdmin”进行以下操作:
清单
6. JMS
provisioning
def qcf(MQ_JMS_MANAGER) qmgr(MQJMS.QManager)
press Enter
def q(JMS_RequestQueue) qmgr(MQJMS.QManager) queue(RequestQueue)
press Enter
def q(JMS_ResponseQueue) qmgr(MQJMS.QManager) queue(ResponseQueue)
press Enter
|
现在,我们已经将队列绑定到JNDI对象中。
3. 启动JMS侦听者程序
现在,可以执行客户端程序来访问“SimpleTransformation”Web服务。
性能
性能研究只针对响应时间而不针对吞吐量。假定客户端是单线程模型。
响应时间
|
传输方案
|
运行10次所用的秒数(每个请求所用的秒数)
|
运行100次所用的秒数(每个请求所用的秒数)
|
运行500次所用的秒数(每个请求所用的秒数)
|
运行10000次所用的秒数(每个请求所用的秒数)
|
运行50000次所用的秒数(每个请求所用的秒数)
| | MAOR MQ | 12(1.2) | 61(0.61) | 285(0.57) | 4941(0.4941) | 24981(0.499) | | AXIS JMS | 11(1.1) | 64(0.64) | 251(0.502) | 4810(0.481) | 26075(0.5215) | | Pure HTTP | 7(0.7) | 49(0.49) | 274(0.548) | 3066(0.306) | 14439(0.288) |
不出所料,最初的JVM启动时间和类的装载对数量少的请求有高的开销。随着请求的数量的增加,这种情况得到了缓解。纯HTTP的情况显示了良好的可伸缩性,表明它也可以用于大容量的通信。
结束语
根据上面的讨论,两种方法都既有优点也有缺点。新的标准还在不断地涌现,而部署的简易性也在日益提高。HTTP是一种更快速和更便宜的解决方案,但是在节省时间和成本的同时损失的却是可靠性。建议在可靠性不是非常重要的情况下使用HTTP,例如,报告消息而不是数值方面的事务。HTTP的可伸缩性也表明,它可以用于高容量的应用。与HTTP相比,在持久化MQ消息上携带SOAP有效负荷有将近60-80%的额外开销。WSDL生成器简化了客户端代码,同时也使部署更容易。从操作的角度来看,两种方法没有什么大的不同。Axis适配器添加处理器(例如验证)更容易。从互操作的角度来看,接口的设计是非常重要的,而很好地理解参数编码也相当关键。
参考资料
作者简介  | |  | Mouli Narayanan is currently a IT Solutions Architect working on building a messaging system for a Wall Street client. After graduating from Pennsylvania State University in 1998 with a Masters degree in Computer Science and Engineering, he joined Torry Harris. Prior to his current project he designed and built dotFlow, an embeddable Java technology workflow engine for J2EE servers. His interests include distributed transaction processing and messaging systems. |
 | |  | Srivathsa is currently a Technical Lead and has been working with Torry Harris Business Solutions for the past 5 years. His area of specialization also includes TP monitors like Transarc Encina and IBM CrossWorlds. He hold an engineering degree in the field of "Electronics and Communication." He has been working on projects involving various enterprise middleware products like IBM WebSphere MQ, WebSphere MQ Integrator, IBM DCE and has also provided enterprise training on WMQ & WMQI. He can be reached at srivathsa_vijay@thbs.com. |
对本文的评价
|