mule in action翻译11 : 2.3 Mule 消息

mule in action翻译11 : 2.3  Mule 消息

2.3  Mule 消息

 当一个消息传入mule, 它实际上是触发了一个事件(例如,可能是org.mule.api.MuleEvent的一个实例)。

 这个事件不仅携带实际的消息本身(例如 一个org.mule.api.MuleMessage实例),而且还包含消息处理时

 用到的上下文信息。 

 事件的上下文由多个不同对象的引用组成,包括安全证书(如果有的话)、处理请求的会话信息和mule的全局上下文信息。 通过上下文可以访问mule的所有内部构件。如图2.7所示 。

 

 

 mule消息由不同的部分组成,如图2.8



 

 1、payload     消息携带的主要内容数据

                         --感觉一个消息就像个拉集装箱的大货车,payload就是大货车拉的集装箱。

 2、properties  包含消息的元数据信息

 3、attachments 这部分是可选的且形式多样,用来支持多段消息(multipart messages)

 4、exception payload  这部分是可选的, 用来保存事件处理过程中发生的任何的错误。

 消息一般由消息源创建。当消息源接收到一个进入事件(如一个HTTP请求或进来一个JMS消息)或者

 成功的轮询了资源(如一个文件系统或一个数据库)都会创建新的消息。

 消息也可以通过编程的方式创建。

 线程安全  默认mule保证在任意一个时间点只有一个线程可以修改消息。

            线程间传递消息的常用的方式是消息复制。

 图2.9展示了HTTP和email 的消息源创建的消息 。

 

 

 如图2.9所示,消息payload的java 类型取决于消息“出身”。

 byte数组,java.io.InputStream的实现类类型,或者字符串,是常见的payload类型。

 一些特殊的payload类型,如 java.io.File对于File传输,也可以由mule消息进行传输。

 payload不会捕获到整个事件的上下文信息,并在mule中传播。消息属性properties登场了。

 2.3.1 消息属性(Message properties )

  消息属性是元数据 ,提供mule携带的payload的上下文数据。

  生成消息(典型的由是inbound endpoint生成)时会自动生成这些元信息。

  当mule分发消息(典型是由outbound endpoint发出)到一个特定目的地时, 也会读取消息属性。

  在消息处理过程中 或 进行消息路由时都会使用到消息属性。

  

  消息属性有一个名字(String),一个值(object)和一个范围(enumeration)组成。

  消息属性包含下面消息:

  1、 一般的传输的元消息   保存在消息属性。想想 http请求头,或JMS的消息属性。

                          一些传输协议如TCP ,不会创建任何的元信息。

  2、 mule特定的传输元信息   用来存储上下文信息。例如 mule收到所有的HTTP请求的请求路线

                             会以 http.request.path的名字保存起来。

  

  

  mule的多数消息传输过程都有outbound endpoints 。这些outbound endpoints对消息属性是“敏感”的。

  例如SMTP传输会自动识别和发送email所需要的元信息相关的所有的 消息属性,如subject或toAddresses。

  

  传输属性  一些传输对属性名字有要求。若你试图使用不符合JMS规范的属性时, 它会进行明确的提示。

  

  不幸的是,并没有一个权威的包含所有属性的列表; 对每个协议你都需要查阅其在线文档。

  另外,我们建议在开发模式下使用logger消息处理器,以显示传输用到的属性消息。

  

  2.3.2 理解属性作用域(property scopes)

  属性在一个范围内有效,但在另一个范围内是无效的。

  这意味着,消息属性不像payloads那样,它在mule内不会一直被自动携带。

  这个“范围”是有边界的,属性并不会被一直传递下去。

  这是边界是如何定义的?

  

  流定义了属性作用域的边界。更确切的说,流的inbound endpoints 和 outbound endpoints 是消息属性传递的边界。

  图2.10 说明了不同的属性作用域 以及相关的边界。

  

 

  

  四种作用域的属性 :

  1、Inbound property     由消息源创建, 这些属性对最终用户是只读的。

                                        Inbound properties可以被outbound endpoints清除;发生这种情况时,

                                       你需要修改你的程序了。

  2、Outbound property  使用set-property, message-properties-transformer 创建,

                                       需要指定scope是outbound 。

                                      也可通过编码创建。

                                      Outbound property由outbound endpoints进行识别。

  3、Invocation property   使用 set-variable, message-properties-transformer创建,

                                        需要指定scope是invocation。

                                       或通过编码生成。

                                       Invocation property主要作为流变量。

  4、Session property   由消息源创建 ,

                                     使用 set-variable, message-properties-transformer 创建,

                                     需要指定scope是session。

                                     也可通过编码创建。

                                      这个作用域一定是对于"飞着的消息"使用(没看明白原文:

                                        this scope is bound to the in-flight message),

                                        可以跨多个流(想一下java的threadlocal 机制,这里差不多是MessageLocal)

                 

    边界交叉   跨作用域时使用 copy-properties元素来复制属性,

                    例如传递一个 inbound property 到 outbound property , 或存储到一个 会话作用域。

目前为止我们只是关注请求阶段的属性。响应阶段是什么样 ?在响应阶段是反过来的。

Inbound endpoints查找outbound作用域的属性,去传递给调用者。

请求-响应的outbound endpoints创建inbound属性 。

只有流和会话变量的行为 在请求和响应阶段都是相同的,

只要它们被保存下来且在消息处理过程中国没有被影响。

列表2.11 展示了 在响应阶段怎么设置HTTP content-type。

如何创建一个属性,才能在inbound endpoint返回给调用者时使用?

秘密在于set-property创建了 outbound 作用域的属性。

Listing 2.11 Adding a header to the outbound scope adds it to the response

<flow name="responseHeader">
        <http:inbound-endpoint exchange-pattern="request-response"
                                           host="localhost"
                                           port="8080"
                                           path="json/data" />
        <component class="com.prancingdonkey.data.JsonDataFetcher" />
        <response>
              <set-property propertyName="Content-Type" value="application/json" />
        </response>
     </flow>

   响应阶段属性的传递  在响应阶段要把一个消息属性从一个outbound endpoint返回给调用

                       inbound endpoint 的调用者,需要把它从inbound拷贝到 outbound 。

   

   

   看另外一个设计多个作用域的例子。列表 2.12显示了一个接受用户输入xml的例子。

   它使用XPath表达式 提取出ID ,并保存为一个名字为useId的流变量。

   这个流变量随后有两个地方使用:

         在一个HTTP outbound endpoint使用它创建一个 REST 资源URI。

         在响应添加一个名字为 X-User-ID的属性。 

  Invocation scope在响应阶段仍是有效的。

  在inbound阶段设置的流变量在响应阶段仍然有效。

Listing 2.12 A flow that sets a variable and uses it in two places

<flow name="flowVarPersistence">
     <vm:inbound-endpoint path="user.fetch" exchange-pattern="request-response" />
     <response>
         <set-property propertyName="X-User-ID" value="#[userId]" />
     </response>
     <set-variable variableName="userId" value="#[xpath('/user/@id').value]" />
     <http:outbound-endpoint address="http://${internalApiBaseUri}/api/users/#[userId]"
                              method="GET"
                     exchange-pattern="request-response" />
</flow>

  可访问但不拥有    尽管流变量和会话变量都可被mule消息的属性访问器访问,

                              但他们实际上却是属于mule的Event 和 Session 对象的。

                             为了方便,mule消息把其引用分享到支持这两个作用域的map中。

  

  

  尽管不经常使用, attachments也是 mule消息的重要成员。

  

  2.3.3 使用消息附件( message attachments)

  

  附件用来支持额外的数据,按严格语义来讲它不是元信息 ,它更像payload的替代品或补充。

  一个附件由一个名字定义、一个数据源(一个 javax.activation.DataHandler )及一个作用域 定义。

  附件的作用域限制在 inbound和outbound,和属性作用域一样有相同的流边界。

  

  附件主要用来支持inbound的email的分段消息(由POP或IMAP创建) 和

  outbound email 消息(使用 SMTP传输)。

  inbound 附件由email endpoint 直接创建,而outbound endpoint的附件需要以编程方式创建。

  

  下面的列表展示了一个流, Prancing Donkey 公司用它接收email订单。

  Listing 2.13 Extracting message attachments with an expression transformer

 
  <flow name="email-order-processor">
      <!-- 1  通过一个在别地配置的全局的 endpoint接收email-->
      <inbound-endpoint ref="email-orders" />
      <!-- 2  提取当前消息所有的附件 -->
      <expression-transformer expression="#[message.inboundAttachments.values()]" />
      <!-- 3  拆分附件列表到单独的每个消息-->
      <collection-splitter />
      <!-- 4  发送一个独立订单消息以进行处理-->
      <outbound-endpoint ref="pdf-orders" />
  </flow>

  

  

  在注释2处,这里使用表达式转换器提取所有的附件,并把当前消息的payload内容替换为所提取的附件列表

                (inboundAttachments  是 java.util.Map  --保存附件的name和value)。

  在注释1后,存储在消息payload中的消息体被丢弃,内容被替换成了附件。

  在注释3处,把附加列表拆分成独立的消息--因为允许客户在一个email中附加几个发票。

  在注释4处,上步被拆分的形成的每个消息 都将由这里调用的服务进行处理。

  

猜你喜欢

转载自yangzhonglei.iteye.com/blog/2090150
今日推荐