mule esb_使用Mule ESB和Groovy编排RESTful服务

mule esb

在过去的几年中,REST风格的软件体系结构已广受欢迎,这主要是因为它通常在需要较少运动部件,松散耦合且更具弹性的系统中得到了改进。

在企业环境中拥有更多的REST资源可用增加了需要以某种方式对它们进行编排的机会。 例如,业务活动通常包括创建资源,随后的查找和其他资源的创建。

从本质上讲,与RESTful服务进行交互非常简单:我们需要形成并发送适当的请求(标​​头和实体),并分析返回的响应(再次标头和实体)。 为此,除了良好的HTTP客户端库以外,不需要特殊的工具或框架。 此外,由于涉及RESTful交互的不同实体是由所谓的微格式定义的,因此轻松解析或输出这些实体的能力也将非常有帮助。

协调与几种资源的交互变得更加复杂。 我们需要定义业务流程,正确处理错误和重试,并且我们的系统必须在负载下正常运行。 作为集成框架,Mule提供了所有这些(以及更多)。

让我们考虑一个示例,一个商人系统,其中对新订单的处理意味着以下编排:

  1. 通过将XML实体发布到服务来创建新订单。
  2. 查找新创建的订单资源并从中提取确认信息。
  3. 指示电子邮件网关根据这些确认信息向客户发送确认消息。

在本文中,我们将详细说明每个步骤的交互作用,并考虑用于实现这种交互作用的特定Mule移动部件和Groovy功能。

整个编排将包括与特定路由器,过滤器和内存中消息队列(又称为VM队列)连接的Mule服务链。 通过阅读有关此主题的最新InfoQ文章,可以了解有关Mule中路由消息的更多信息。

Mule中的REST支持

Mule提供了一种使用Mule RESTPack与RESTFul服务进行交互的简单但功能非常强大的方法。

Mule RESTPack提供了一套全面的连接器和指南,可帮助您创建新的RESTful应用程序。 在撰写本文时,该包提供了三种基于流行的与REST相关的框架的传输:Abdera,Jersey和Restlet。 这对于公开新资源非常方便,但是如何集成现有的REST资源呢?

好消息是,借助Mule的标准HTTP脚本模块提供的Groovy支持,Mule的常规HTTP传输得到了增强,您将获得成功与RESTful服务进行交互所需的一切。

用M子发布

让我们开始第一个交互。 通过HTTP将XML实体发布到特定资源来创建订单,如以下摘录所示:

POST /orders HTTP 1.1
...
<order xmlns='urn:acme:order:3:1'>
   <customerId>123456</customerId>
   <productId>P987C</productId>
   <quantity>2</quantity>
</order>

服务器在成功的情况下答复的信息:

201 Created 
Location: http://acme.com/order/O13579 
... 
<order id='O13579' />

此交互是在Mule中使用简单的HTTP出站终结点实现的。 请注意,互动本身是通过将包含所需值(客户和产品ID,数量)的映射发送到订单创建服务来触发的。 那么这项服务是什么样的呢? 这里是:

<service name="OrderCreationService"> 
  <inbound> 
    <inbound-endpoint ref="OrderCreationQueue" /> 
  </inbound> 
  <outbound> 
    <chaining-router> 
        <http:outbound-endpoint synchronous="true" 
              responseTimeout="15" method="POST" 
              host="${acme.order.hostname}" 
              port="${acme.order.port}" path="orders" 
              user="${acme.order.username}" 
              password="${acme.order.password}" 
              contentType="application/vnd.acme+xml" encoding="UTF-8"> 
              <transformers> 
                <transformer ref="OrderMapToMicroformat" /> 
              </transformers> 
              <response-transformers> 
                  <message-properties-transformer> 
                        <add-message-property key="OrderPlaced" 
                            value="#[groovy:message.getStringProperty('http.status','ERR')=='201']" /> 
                        <add-message-property 
                            key="OrderResourceLocation" 
                            value="#[groovy:message.getStringProperty('Location','')]" /> 
                  </message-properties-transformer> 
                  <object-to-string-transformer /> 
              </response-transformers> 
         </http:outbound-endpoint> 
         <outbound-endpoint ref="OrderCreationResultQueue" /> 
   </chaining-router>     
  </outbound> 
</service>

那是相当密集的XML,所以让我们仔细看看这里的内容:

  • 在名为OrderCreationQueue的通道(可以是VM队列或JMS队列)中接收到一条消息,
  • 接收到的消息直接传递到路由器,该路由器将HTTP POST的结果链接到另一个服务,该服务通过名为OrderCreationResultQueue(异步VM队列)的通道来分析呼叫的结果。
  • HTTP发布是在Groovy转换器类固醇上使用标准出站端点执行的:
    • 所需的订单微格式是使用下一节中详细介绍的特定转换器创建的。
    • 由于使用了一个微型脚本,因此提取了结果代码并将其与期望值进行比较。 我们在此处进行比较,以便将后续服务与纯HTTP问题隔离开:我们创建的boolean OrderPlaced属性是真正中立的,并具有与正在进行的业务流程相关的名称。
    • 同样,我们将位置标头复制到更有意义的OrderResourceLocation名称下。 在执行此操作时,请注意我们如何处理该标头可能丢失(在失败的情况下)并默认为空字符串的事实,以避免在消息中添加null属性(这会使Mule踢回您)。
  • 我们使用object-to-string-transformer来“分离”作为流返回的HTTP响应。 多亏了它,使用与HTTP交换相关的编码,流被完全消耗,并且其内容转换为字符串。 当此流关闭时,HTTP连接将释放:我们不想一直保持打开状态,等待后续服务在OrderCreationResultQueue中拾取响应消息。

Groovy的MarkupBuilder优点

这项服务的繁重工作实际上是由OrderMapToMicroformat转换器完成的,该转换器本身由Groovy的MarkupBuilder驱动 。 MarkupBuilder API提供了一种自然的方式来生成符合我们特定微格式的XML实体:

<scripting:transformer name="OrderMapToMicroformat"> 
   <scripting:script engine="groovy"> <![CDATA[ 
        def writer = new StringWriter() 
        def xml = new groovy.xml.MarkupBuilder(writer) 
        xml.order(xmlns: 'urn:acme:order:3:1') { 
          customerId(payload.clientId) 
          productId(payload.productCode) 
          quantity(payload.quantity) 
        } 
        result = writer.toString() ]]> 
    </scripting:script> 
</scripting:transformer>

请注意,如何使用地图有效负载中的值填充XML元素:此处解决了一些命名约定不匹配的问题(例如,clientId成为customerId)。

根据需要,该变压器产生这种输出:

<order xmlns='urn:acme:order:3:1'> 
   <customerId>123456</customerId> 
   <productId>P987C</productId> 
   <quantity>2</quantity> 
</order>

并且,除了正确的内容类型之外,RESTful服务创建新资源所期望的就是所有这些。

分析一下

现在让我们看一下负责异步分析订单创建结果并确定编排是否值得进一步进行的服务:

<service name="OrderCreationResultProcessor"> 
  <inbound> 
    <inbound-endpoint ref="OrderCreationResultQueue" /> 
     <selective-consumer-router> 
        <message-property-filter pattern="OrderPlaced=true" /> 
     </selective-consumer-router> 
     <logging-catch-all-strategy /> 
  </inbound> 
  <outbound> 
    <pass-through-router> 
      <outbound-endpoint ref="SuccessfulOrderQueue" /> 
    </pass-through-router> 
  </outbound> 
</service>

我们使用选择性使用者来仅接受带有标头的消息,以确认订单已成功下达。 如果此标头为true,则我们通过名为SuccessOrderQueue的内存队列将消息路由到专用于处理成功订单创建消息的第三个也是最后一个服务。 请注意,在此示例中,我们仅记录不符合要求的消息,但实际上,我们会将错误消息发送到专用队列,以供以后的取证或立即反馈给应用程序。

M子入门

组成业务流程的最终服务是通过HTTP来获取新创建的订单的,该订单包含为电子邮件网关形成有效消息所需的额外值。 这是一个示例交互:

GET /order/O13579 HTTP 1.1 
200 OK 
Content-Type: application/vnd.acme+xml 
... 
<order xmlns='urn:acme:order:3:1'> 
  <customerId>123456</customerId> 
  <productId>P987C</productId> 
  <quantity>2</quantity> 
  <customerEmail>foo@bar.baz</customerEmail> 
  <estimatedShipping>2009-31-12T00:00:00Z</estimatedShipping>
</order>

好消息是,Mule的库存HTTP传输包含一个组件(称为rest-servicecomponent),该组件可促进与服务中的REST资源进行交互。 由于有了这个组件,我们不需要将GET操作的结果链接到后续服务,而是可以在单个服务中执行所有操作。 此外,它支持在其配置中使用表达式,从而支持与动态构建的URL的连接。

这是最后一个服务的样子:

<service name="SuccessfulOrderProcessor"> 
<inbound> 
  <inbound-endpoint ref="SuccessfulOrderQueue" /> 
</inbound> 
<http:rest-service-component httpMethod="GET" 
   serviceUrl="#[header:OrderResourceLocation]" /> 
<outbound> 
  <pass-through-router> 
    <outbound-endpoint ref="EmailGatewayQueue"> 
      <transformers> 
       <object-to-string-transformer /> 
       <transformer ref="OrderMicroformatToEmailMap" /> 
      </transformers> 
    </outbound-endpoint> 
  </pass-through-router> 
</outbound> 
</service>

收到成功的订购消息后,此服务使用REST服务组件生成对URL的HTTP GET请求,该请求先前已存储在名为OrderResourceLocation的属性(即标头)中。 请注意我们如何使用Mule表达式评估框架(具有#[...]语法)在此组件中注入动态URL。

在将GET请求的响应传递给负责与电子邮件网关进行通信的服务之前,我们对XML订单实体执行两个转换:

  • 如前所述,我们“分离”了响应实体。
  • 我们使用转换器来解析XML实体并构建下一个服务期望的映射。 为此,我们再次依靠Groovy的力量。

Groovy的XmlSlurper幸福

Groovy的XmlSlurper得益于其类似DSL的API,是解析XML微格式的理想工具。

这是OrderMicroformatToEmailMap转换器内部的内容:

<scripting:transformer name="OrderMicroformatToEmailMap"> 
  <scripting:script engine="groovy"><![CDATA[ 
    def order = new XmlSlurper().parseText(payload)
				.declareNamespace(acme: 'urn:acme:order:3:1') 
    result = [emailId:'OrderConfirmation', 
		emailAddress:order.'acme:customerEmail'.text(), 
		orderId:order.@id.text()] 
   ]]> 
  </scripting:script> 
</scripting:transformer>

是的,这是Groovy的两行,我们有一个支持名称空间的XML解析器和一个地图生成器。 真是太好了! 但这就是我们创建电子邮件网关服务所期望的地图所需要的。

终于休息

在本文中,我们遵循了一个非常预定义的编排路径,新的订单资源URL是唯一的动态位。 不难想象,如果决定走HATEOAS之路 ,您将如何利用演示的转换器和表达式来支持更多的动态交互。 如果是这样的话,其他Mule的智能路由器将变得很方便,例如允许您创建幂等接收器的智能路由器。 您已经看到了Groovy的功能和简洁性以及Mule的通信能力如何极大地简化了与RESTfull服务的交互。 Mule的表达式和微小的Groovy脚本都是动态化Mule配置的有效方法。 此外,由于使用了Mule固有的SEDA体系结构,我们使用异步VM队列来链接业务流程的不同步骤,这使我们的解决方案能够在峰值负载下正常降级。

有了所有这些强大的工具,集成REST资源肯定不会使您感到不安。

请享用!

完整的配置和相关的测试资源可以作为独立的Maven项目获得,您可以在这里获得: http : //dossot.net/datastore/mule-groovy-rest.tar.gz

翻译自: https://www.infoq.com/articles/restful-services-mule/?topicPageSponsorship=c1246725-b0a7-43a6-9ef9-68102c8d48e1

mule esb

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值