Apache Synapse 是一个简单、轻量级的高性能企业服务总线 (ESB),它是在 Apache Software Foundation 的 Apache License Version 2.0 下发布的。使用 Apache Synapse,您可以通过 HTTP、HTTPS、Java™ Message Service (JMS)、简单邮件传输协议 (SMTP)、邮局协议版本 3 (POP3)、FTP、文件系统和许多其他传输介质筛选、转换、路由、操作和监视经过大型企业系统的 SOAP、二进制文件、XML 和纯文本消息。但是对于单个开发人员来说,ESB 产品在您的日常生活中有何作用呢?简化的配置、即时可用的功能集、可扩展的体系结构和小巧的脚本使得它成为一个强大的多用途工具,您可以利用它完成各种任务。本文将向您介绍如何使用 Apache Synapse 创建模拟 Web 服务。
开始之前
关于本教程
本教程讨论如何使用 Apache Synapse ESB 创建模拟 Web 服务。目标 Web 服务客户端和服务可以使用任何语言,如 Microsoft® .NET、Java 或 PHP。您将学习几个示例,从最基本的配置开始,然后逐渐构建更加复杂的解决方案,以创建模拟 Web 服务。
先决条件
本教程主要是为 Web 服务开发人员编写的,因此,您应大致熟悉一些 Web 服务概念。具备 Apache Synapse 方面的知识对理解本文非常有用。您还必须至少掌握关于 XSL 传输 (XSLT) 和 JavaScript 代码的基本知识。如果您不熟悉这些知识领域,网络上有许多资源可为您提供一些基本信息。
系统要求
Apache Synapse 需要 JDK 1.5,可以在 Linux®、Microsoft Windows® 和 Solaris 环境中运行。内存和磁盘空间要求较低,因此,您可以在低端系统上轻松地运行它,而且不会出现任何问题。
在本教程中,命令和目录名称将以 Linux 兼容格式提供。如果您的操作系统是其他系统,请相应地更改命令和目录名称。例如,在 Windows 中,您必须使用 synapse.bat 脚本(而不是 synapse.sh)来启动 Synapse 实例。
什么是模拟 Web 服务,我为什么要使用它们?
在您的日常工作中,您可能会遇到以下四种情形:
您的上司要求您编写一个依赖于一个或多个远程 Web 服务的程序。这些 Web 服务可以在生产服务器中运行,但在测试服务器中可能不可用。对于第三方服务,您甚至无权访问代码或二进制文件。因此,您必须从头开始组装一些模拟服务来测试您的代码。可能的情景是,您没有针对生产服务器通过预订和稍后取消预订测试您已对旅馆预订系统所做的错误修复。或者说您是否打算做这些工作?
您也许正在家中、路上或飞行途中办公,并且您需要一整套脱机运行的 Web 服务,以便能够尝试您对订购处理系统所做的最新修改。此系统通过目录服务检查产品并通过订购处理服务下订单。
您希望创建一个脱机演示,但是又不能确定是否可以访问远程 Web 服务并且该服务是否始终可以运行。您需要确保,当潜在客户坐在您面前时,Web 服务调用能够正确响应——即无连接超时意外。
您可能需要模拟不同的情形。如果出现服务响应错误,或者出现意外响应,情况会是怎么样?可能很难获得您希望从托管的测试服务获得的准确响应。在投入生产两周之后,您的程序可能尚未针对 rooms not available 错误响应进行过测试,直到出现了此问题。
在所有这些情形中,您可以通过创建假 Web 服务(即模拟 Web 服务)模仿实际 Web 服务的行为来解决这些问题。模拟 Web 服务具有与实际 Web 服务相同的界面和行为。在开发和测试期间,您可以将实际的 Web 服务端点与模拟 Web 服务端点进行交换。这可以让您对外部 Web 服务调用验证请求消息并传回必需的响应消息。
Apache Synapse 解决方案
有关将 Apache Synapse 用于模拟 Web 服务的好处是,当解决此任务中的企业集成问题时,您可以应用使用 ESB 时所获得的相同技能和方法,而无需学习和投资其他工具。您可以使用可用的工具、脚本语言、样式表甚至 Java 代码,以您希望的方式转换和处理这些响应。
假定您已经安装并运行了某些 Apache Synapse 示例。Apache Synapse 带有大量的示例,您可以在绑定的示例服务器和客户端的帮助下尝试这些示例(请参阅下载部分)。如果尚未这样做,请进入 Apache Synapse 网站并下载最新的版本(请参阅参考资料部分以获取相关链接)。查看示例指南,并尝试其中的一些示例。按照该指南中的分步说明,您可以立即开始操作。在本文中,通过使用某些 Synapse 配置,您将在 Apache Synapse 中使用相同的示例客户端并模拟同一示例服务器行为。
Synapse 配置是用特定于域的语言编写的 XML 文件,您可以使用它告诉 Synapse 应该对所接收到的消息执行什么操作。
在这些示例中,您将使用简单的 XSL 样式表和脚本代码。即便您不熟悉这些内容,也可以修改提供的示例,并利用它们轻松满足您的需要。
设置示例
首先您要安装 Apache Synapse 并准备环境,以便试验这些示例:
下载最新版本的 Apache Synapse,并将分发版本解压缩到一个目录中(请参阅参考资料,以获取下载 Apache Synapse 的链接)。
如果您还没有安装 JDK 1.5,请安装 JDK 1.5 并将 JAVA_HOME 环境变量指向它的安装目录。
安装 Apache Ant,把 Apache Ant bin 目录添加到 PATH 环境变量中(请参阅参考资料以获取相关链接)。
从下载部分中下载示例包,并将其解压缩到一个目录中。
从示例包中,将 mocks 目录复制到 Apache Synapse repository/conf/sample/resources 目录中。图 1 显示了在 Synapse 目录结构中复制这些文件的位置。
将五个 Synapse 配置文件复制到 Apache Synapse repository/conf/sample 目录中(参见图 1)。
图 1. 示例文件的位置
您可以使用 Synapse 用来启动绑定示例配置的同一机制来尝试 Synapse 示例配置文件。这就是为什么这些配置文件被命名为 synapse_sample_*.xml 并位于该示例目录中的原因。
已编写了与 Synapse 分发版绑定的示例客户端,以便生成不同类型的请求、处理其响应,并显示输出。(有关详细信息,请参阅参考资料部分中的 Synapse 示例指南。)
在运行客户端时,您可以使用 Apache TCPMon 之类的工具来查看发生了什么情况(请参阅参考资料以获取相关链接)。配置监视工具以便在 8081 上侦听,然后转发给端口 8080。您在设置该工具来截获在该客户端和 Synapse 之间交换的消息。TCPMon 显示客户端在发送什么内容,Synapse 在发回什么内容。如果您没有使用 TCPMon,请在稍后运行示例客户端命令时,将端口 8081 替换为 8080。
大功告成。现在您可以利用 Apache Synapse 启动绑定模拟 Web 服务了。您可以从最简单的示例开始,然后逐渐构建比较复杂的配置。
示例请求和响应
首先您将模拟最简单的示例场景:指示 Apache Synapse 无论接收到什么请求都要发送固定的响应:
通过进入 Synapse bin 目录并用命令
./synapse.sh -sample mock1-simple
,使用 synapse_sample_mock1-simple.xml 配置启动 Synapse。这将使用 synapse_sample_mock1-simple.xml 配置启动 Synapse 实例,它是您在前面复制到 repository/conf/sample 中的文件。
在 Synapse 启动后,进入 Synapse samples/axis2Client 目录,并像如下所示运行示例客户端:
ant stockquote -Dtrpurl=http://localhost:8081/
。
该示例客户端将为符号 IBM 创建
getQuote
操作请求,并将其发送到端点地址 http://localhost:8081/soap/StockQuote。然后打印从接收的响应中提取的股票价格。如果您正在使用 TCPMon 之类的工具,则可以看到,客户端在发送一个
getQuote
操作请求消息,并且 Synapse 在发送回一个
getQuoteResponse
响应消息。
注意,这类似于 Synapse 示例指南中的示例 0(请参阅参考资料以获取相关链接)。但您没有使用 Addressing 标头。这是为了尽可能使该示例简单易懂。您未使用示例服务器;而是使用 Synapse 模拟了服务器响应。清单 1 显示了您已经使用的 Synapse 配置。
清单 1. 用于简单请求和响应的 Synapse 配置:synapse_sample_mock1-simple.xml
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="GetQuoteResponse_xsl"
src="file:repository/conf/sample/resources/mocks/GetQuoteResponse.xsl"/>
<in>
<xslt key="GetQuoteResponse_xsl"/>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send />
</in>
</definitions>
在配置中,您已经使用简单的样式表转换将请求消息内容替换为响应消息内容,并将其标识为响应,以便 Synapse 将它返回给请求者。您还删除了 WS Addressing 标头(如果存在)。否则,Synapse 将使用该标头来提供消息。在此最简单的案例中,无论该请求是什么,您都将 Synapse 配置为发回此固定消息。您可以利用不同的请求消息尝试调用此端点;它会用相同的响应消息回复。您可以更改样式表中的消息内容并更改 Synapse 响应。现在使用
ant stockquote -Dtrpurl=http://localhost:8081/ -Dmode=fullquote -Dsymbol=ABC
按如下所示运行示例客户端。这将为符号 ABC 发送完整的股票报价请求。
如果您监视该请求消息,则可以看到这次是
getFullQuote
操作请求消息,并带有股票符号 ABC。但是 Synapse 仍像以前那样发送同样的响应。
清单 2 是您用过的样式表 GetQuoteResponse.xsl。您只是将当前的请求消息替换为响应消息内容。
清单 2. 用于简单请求和响应的样式表:GetQuoteResponse.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getQuoteResponse xmlns:ns="http://services.samples/xsd">
<ns:return type="samples.services.GetQuoteResponse">
<ns:change>-2.920874334221886</ns:change>
...
<ns:symbol>IBM</ns:symbol>
<ns:volume>9343</ns:volume>
</ns:return>
</ns:getQuoteResponse>
</soapenv:Body>
</soapenv:Envelope>
</xsl:template>
</xsl:stylesheet>
在清单 2 中,您已经定义了隐式主序列。位于顶层中的所有中介器元素(例如,此实例中的 in 中介器)均属于该序列。Synapse 接收的每个请求均通过此序列。在下面的示例中,您承载了一个虚拟 Web 服务,该服务有其自己的端点地址及其本身的 Web 服务描述语言 (WSDL)。
设置代理服务
这一次,您在 Synapse 中承载一个虚拟 Web 服务,它将像前述示例那样返回预定义的响应消息。此外,该虚拟 Web 服务将发布您自定义的、用来模拟实际 Web 服务的 WSDL。此示例类似于 Synapse 示例指南中的简单代理服务示例 150(请参阅参考资料以获取相关链接)。
按如下所示,从 synapse_sample_mock2-proxy.xml 配置启动 Synapse:
./synapse.sh -sample mock2-proxy
。
要查看 Web 服务 WSDL,请在 Web 浏览器中转到 http://localhost:8080/soap/StockQuoteService?wsdl。这是您为该代理服务提供的自定义 WSDL。
您可以使用
ant stockquote -Dtrpurl=http://localhost:8081/soap/StockQuoteService
运行示例客户端。
您可以像在以前示例中那样获取股票报价。在本例中,您已经将该请求消息发送到承载该代理服务的位置。清单 3 是您使用的 Synapse 配置。
清单 3. 用于设置代理服务的 Synapse 配置:synapse_sample_mock2-proxy.xml
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="GetQuoteResponse_xsl"
src="file:repository/conf/sample/resources/mocks/GetQuoteResponse.xsl"/>
<proxy name="StockQuoteService">
<target>
<inSequence>
<xslt key="GetQuoteResponse_xsl"/>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send/>
</inSequence>
<outSequence/>
</target>
<publishWSDL
uri="file:repository/conf/sample/resources/mocks/SimpleStockQuoteService.wsdl"/>
</proxy>
</definitions>
在此场景中,您定义了名为
StockQuoteService
的代理服务。顾名思义,代理服务 就是在 ESB 中运行的虚拟服务。它有确切的端点位置,并且您可以为该服务提供自定义的 WSDL,以便此服务行为与驻留在远程服务器中的其他任何 Web 服务完全一样。
假设您在为远程生产服务构建客户端。您可以获取 WSDL,像这样承载该语言并处理请求消息,以便在几分钟内模拟实际服务。您甚至可以设置 WS-Security、WS-ReliableMessaging 和此服务的其他附加项,以便模拟具体的实际情形。您可以使用 Synapse 轻松地将这些服务质量 (QoS) 附加项添加到现有的生产服务中。
发送到此服务的请求消息将通过
inSequence
中的中介器。
inSequence
内容与前一示例中的 in 中介器的内容一样。您已将该请求消息替换为响应消息并将其标识为响应消息。
此配置不包含主序列。您只处理由虚拟服务
StockQuoteService
接收的请求消息。如果您像前面的实例那样将请求消息发送至 http://localhost:8081/,Synapse 将记录该消息并丢弃它。这是没有主序列时的缺省行为。
您已经在 ESB 中成功承载了虚拟服务。现在将请求消息有效负载替换为给定的响应,并将其标识为响应,以便 Synapse 发送回该响应,该响应就像来自示例服务器那样。
到现在为止,您已经将固定响应消息发送到了所有接收的请求消息。接下来您将了解如何根据请求消息内容自定义响应消息。
带有自定义响应的代理服务
在本示例中,不是发送固定的响应,而是根据请求消息内容更改响应。正如在前述示例中那样,您使用样式表将请求消息转换为响应消息,同时从该请求消息中提取一些值并将其放入响应消息中。
使用 synapse_sample_mock3-customquote.xml 配置启动 Synapse:
./synapse.sh -sample mock3-customquote
。
使用
ant stockquote -Dtrpurl=http://localhost:8081/soap/StockQuoteService -Dsymbol=ABC
运行示例客户端。
如果您监视响应消息,则可以看到它具有与请求消息中相同的符号。更改该符号值并再次运行它。该响应消息将包括给定的请求符号值。
清单 4 是您使用的 Synapse 配置。
清单 4. 具有自定义响应的代理服务的 Synapse 配置:synapse_sample_mock3-customquote.xml
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="CustomGetQuoteResponse_xsl"
src="file:repository/conf/sample/resources/mocks/CustomGetQuoteResponse.xsl"/>
<proxy name="StockQuoteService">
<target>
<inSequence>
<xslt key="CustomGetQuoteResponse_xsl"/>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send/>
</inSequence>
<outSequence/>
</target>
<publishWSDL
uri="file:repository/conf/sample/resources/mocks/SimpleStockQuoteService.wsdl"/>
</proxy>
</definitions>
您的样式表将从请求消息中提取内容并使用其中的一些内容自定义该响应。在本例中,您仅使用了
<xsl:value-of/>
元素来提取请求数据,并将其放在响应消息中。
清单 5. 具有自定义响应的代理服务的样式表:CustomGetQuoteResponse.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="/">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getQuoteResponse xmlns:ns="http://services.samples/xsd">
<ns:return type="samples.services.GetQuoteResponse">
<ns:change>-2.920874334221886</ns:change>
...
<ns:symbol><xsl:value-of
select="ns:getQuote/ns:request/ns:symbol"/></ns:symbol>
<ns:volume>9343</ns:volume>
</ns:return>
</ns:getQuoteResponse>
</soapenv:Body>
</soapenv:Envelope>
</xsl:template>
</xsl:stylesheet>
在此示例中,您使用样式表转换构建了一个合适的响应消息,该响应消息使用了从请求消息中提取的内容。如果查看此 Web 服务中的 WSDL,您可以看到在此 Web 服务中还有三种操作。此时,对于发送到此代理服务的任何请求消息类型,Synapse 都将发送同样的响应。在下面的部分中,您将执行 Web 服务的其他操作。
完整代理服务
现在,让我们使用样式表转换来实现一套完整的股票报价服务操作。您将测试请求消息中的操作名称元素,并用合适的响应替换它。
使用 synapse_sample_mock4-fullservice.xml 配置启动 Synapse:
./synapse.sh -sample mock4-fullservice
。
如下所示运行示例客户端:
ant stockquote -Dtrpurl=http://localhost:8081/soap/StockQuoteService -Dmode=quote
。
将
quote
的值分别更改为
fullquote
、
marketactivity
和
placeorder
,并运行以上命令。示例客户端在每个情形中将发送不同的请求类型。Synapse 将根据发送的请求消息发送合适的响应。
清单 6 是您使用的 Synapse 配置。
清单 6. 完全代理服务的 Synapse 配置:synapse_sample_mock4-fullservice.xml
<definitions xmlns="http://ws.apache.org/ns/synapse">
<localEntry key="SimpleStockQuoteService_xsl"
src="file:repository/conf/sample/resources/mocks/SimpleStockQuoteService.xsl"/>
<proxy name="StockQuoteService"> <target>
<inSequence>
<filter xpath="//ns:placeOrder"
xmlns:ns="http://services.samples/xsd">
<log format="full" />
<drop />
</filter>
<xslt key="SimpleStockQuoteService_xsl"/>
<property name="RESPONSE" value="true"/>
<header name="To" action="remove"/>
<send/>
</inSequence>
<outSequence/>
</target>
<publishWSDL
uri="file:repository/conf/sample/resources/mocks/SimpleStockQuoteService.wsdl"/>
</proxy>
</definitions>
在样式表中,您将测试请求消息是什么并用合适的响应消息替换这些内容。
placeOrder
操作是一种例外情形,它是一种仅传入操作。这意味着
placeOrder
操作没有响应。您使用筛选器中介器测试了该请求是否包含使用 XPath 表达式的
placeOrder
元素。如果是,就已经记录了该请求并丢弃了该消息,以防出现进一步中介。这不会像预期的
placeOrder
操作那样将响应发送回客户端。
清单 7 是用于完整代理服务的样式表。您将使用操作名称检查这些元素,并在发现时将该消息替换为合适的响应消息。
清单 7. 完全代理服务的样式表:SimpleStockQuoteService.xsl
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns="http://services.samples/xsd">
<xsl:output method="xml"/>
<xsl:template match="/">
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<xsl:if test="ns:getQuote">
<ns:getQuoteResponse >
...
</ns:getQuoteResponse>
</xsl:if>
<xsl:if test="ns:getFullQuote">
<ns:getFullQuoteResponse
xmlns:ns="http://services.samples/xsd">
...
</ns:getFullQuoteResponse>
</xsl:if>
<xsl:if test="ns:getMarketActivity">
<ns:getMarketActivityResponse xmlns:ns="http://services.samples/xsd">
...
</ns:getMarketActivityResponse>
</xsl:if>
</soapenv:Body>
</soapenv:Envelope>
</xsl:template>
</xsl:stylesheet>
您已经使用了一个简单的样式表在 Synapse 中成功模拟了完整的 Web 服务操作。在接下来的部分中,您要将其他虚拟 Web 服务添加到现有配置中。
服务组
在本步骤中,您将添加另一项虚拟 Web 服务 LBService1。LBService1 是另一个 Web 服务,它随 Synapse 中绑定的示例服务器提供,用于演示负载平衡和故障切换示例。这里您仅在 Synapse 中进行模拟。
使用 synapse_sample_mock5-twoproxy.xml 配置启动 Synapse:
./synapse.sh -sample mock5-twoproxy
。