? 前面3篇基本都围绕在loanBroker例子的背景和外围知识上了,只有上篇开头说明了如何改造loanBroker使得可以在eclipse内部启动调试,花费时间学了背景知识不是浪费时间,磨刀不误砍柴工,对例子的了解加深了许多。下面在改造的配置文件基础上详细分析loanBroker。从上到下逐条分析配置文件的配置项:
? 1、
<jms:activemq-connector name="jmsConnector"/>
? 配置了使用ActiveMQ实现的JMS队列连接器,参考users-guide的JMS Transport一节。
? 2、
<!-- custom transformers that implements the Mule Transformer API --> <custom-transformer name="RestRequestToCustomerRequest" class="org.mule.example.loanbroker.transformers.RestRequestToCustomerRequest" />
? 这是个自定义转换器、没啥说的、想看转换器咋写自己去看,下次要用转换就复制黏贴、改巴改巴、o了。这个转换器把rest字符串形式的请求消息转为对象形式的消息:CustomerQuoteRequest(包含Customer)
? 3、
<custom-transformer name="CreditProfileXmlToCreditProfile" class="org.mule.example.loanbroker.transformers.CreditProfileXmlToCreditProfile" /> <expression-transformer name="CustomerToCreditProfileArgs"> <return-argument evaluator="bean" expression="name"/> <return-argument evaluator="bean" expression="ssn"/> </expression-transformer>
? 这是两个被原来的ejb所引用的转换器,因为外部CA服务的方法参数与mule的接口CreditAgencyService不符,但在使用了DefaultCreditAgency以后就不存在方法参数不符问题了,所以这两个转换器也都用不到了已经。不过CreditProfileXmlToCreditProfile是个更复杂的转换器也可以结合原有EJB来看看,它的作用是用dom4j的xpath提取功能从EJB返回的xml文档中提取出customer-history客户信用记录和credit-score信用积分。
? 第二个expression-transformer表达式转换器:在当前消息上执行数个表达式...返回对每个表达式求值后的结果对象数组,它的子元素只有一个:return-argument(一个表达式),上面的配置望文生义,就是指计算对象(evaluator)是个pojo bean、表达式就可以直接写这个pojo的属性名,相当于调用getName、getSsn方法,作用是在向EJB请求之前提取出客户的name和ssn作为请求ejb的参数。
4、
<!-- The Message properties transformer can be used to add, modify or delete properties on the current message. In this instance we use a groovy expression to get a List of endpoints from each of the lenders and set them as a property on the message called 'recipients'--> <message-properties-transformer name="SetLendersAsRecipients"> <add-message-property key="recipients" value="#[groovy:payload.lenders.endpoint]"/> </message-properties-transformer>
? 这是个消息属性转换器,至于用到了哪里请自己去看免得这里跑题太远。消息属性转换器可以为一条消息增加修改删除属性(这个属性放在了哪里我暂时没查到,现在看这最像是JMS的一种机制就是在JMS容器内的消息可以随意附加额外属性,更像是消息附件)。这里是使用groovy表达式 遍历LoanBrokerQuoteRequest(payloaders)对象的Bank[] lenders、把每一个Bank对象的String endpoint这个属性拿出来、组合成一个以recipients为键的消息属性。至于表达式: 表达式允许你从当前消息当中提取信息、或者是决定如何处理消息——特别是在路由和过滤的时候、用来定义路由规则和过滤掉不想要消息的过滤规则(作用类似正则表达式+xpath、找出匹配项、总之就是按条件甄选消息)一些过滤器和路由器都是为使用表达式而特别设计的、只有它们有evaluator(表达式运算对象)和expression属性例如下面的过滤器求值每条消息的header头并抽取头中具有origin-country属性为"USA"的消息:
<expression-filter evaluator="header" expression="origin-country=USA"/>
? 对于其他过滤器、路由器、转换器以及属性,你可以像这样添加表达式:#[<evaluator>:<expression>]?
? 如下表达式将消息头中的ID加入消息属性,用的是XPath表达式:
<message-properties-transformer> <add-property name="GUID" value="#[xpath:/msg/header/ID]/> </message-properties-transformer>
? 更多请参阅mule-2.2.1-users-guid手册倒数第二节Using Expressions
? Mule 2.2中,现在你可以使用强大的新的Mule表达式语言(mule中的表达式比较重要类似camel在serviceMix的作用),它提供了一种通用语言用于查询消息属性、attachments payload、Mule上下文信息如当前服务或端点,并且访问注册器...
? 5、
<!-- Example of a built-in, transport specific transformer --> <jms:object-to-jmsmessage-transformer name="ObjectToJMSMessage" />
? 对象要走JMS消息通道之前得经过转换,mule提供了默认转换器。还可以参考:
? 6、
<endpoint name="CustomerRequestsREST" address="jetty:rest://localhost:8888/loanbroker" /><!--http://localhost:8888/loanbroker/?customerName=RossMason&ssn=1234&loanAmount=10000&loanDuration=24--> <endpoint name="CustomerRequests" address="vm://customer.requests" /><!-- console prompt -->
? 这两个端点都是<service name="LoanBroker">xx中介服务 的入站端点,也就是都是消息流的起点,{dy}个是用来接收客户请求的jetty rest服务、第二个是接收来自控制台输入的客户请求——但它并不是stdio,我们上回提过要从控制台输入的话得以java application方式运行LoanBrokerApp、参见其main方法的:
? loanBrokerApp.run -> AbstractLoanBrokerApp.run -> 我们都是选择1 -> 进入AbstractLoanBrokerApp.request方法注意到里面的这行代码:
client.dispatch("CustomerRequests", request, null);
? CustomerRequests正是第二个端点的名称,而client则是一个MuleClient,request是CustomerQuoteRequest类型是组织好的客户输入信息,也就是说MuleClient借助mule API可以与mule server相通讯、像上面那样指定端点的名字就可以向端点发消息了。
? 这两个输入端点在xx中介服务 的入站配置是这样的:
<inbound> <inbound-endpoint ref="CustomerRequestsREST" transformer-refs="RestRequestToCustomerRequest" /> <inbound-endpoint ref="CustomerRequests" /> </inbound>
? {dy}个端点消息进入后需要经过转换转换为CustomerQuoteRequest类型、第二个端点client发送的就是CustomerQuoteRequest类型所以无需转换。
?
7、
<endpoint name="CustomerResponses" address="replyLoanQuotes" /> <endpoint name="replyLoanQuotes" address="jms://esb.loan.quotes" /> <endpoint name="CreditAgencyGateway" address="jms://esb.credit.agency" />
? {dy}个端点没用(因为无处引用并且注释掉后无影响)
? 第三个端点:xx中介服务 -> CreditAgencyGateway -> <service name="CreditAgencyGatewayService">征信所网关服务
? 第二个很重要,是<service name="BankingGatewayService">银行网关服务 的出站:
<reply-to address="replyLoanQuotes" />
?以及xx中介服务 的异步应答器的入站:
<async-reply timeout="10000"> <inbound-endpoint ref="replyLoanQuotes" /> ........
? 我们说过异步应答器的重要性,在这里再说一下,异步应答器在配置上属于service的一部分,本来按照SEDA一个service就是一个stage,但是个人认为异步应答器在运行时是作为新线程启动运行的,这也是“异步”的含义,service运行结束之前会启动新线程运行异步应答器然后自身就结束了,异步应答器运行起来以后会在它自己的入站端点上起一个监听,监听收集从远方回来的消息应答。
?
8、<ejb:endpoint...这个端点已经改为:
<endpoint name="CreditAgency" address="vm://local.CreditAgency.getCreditProfile" />?
9、
<endpoint name="LenderGateway" address="jms://esb.lender.service" /> <endpoint name="LenderService" address="vm://lender.service" /> <endpoint name="BankingGateway" address="jms://esb.banks" />
?? {dy}个端点:<service name="CreditAgencyGatewayService">征信所网关服务 -> LenderGateway -> <service name="LenderGatewayService">贷方网关服务 ,是连接这两个服务的jms端点,官网上例子结构图的jms部分都画在一起了是一条总线,不过这里感觉和vm一样都是点对点的而且是有数条管道。
? 第二个端点:贷方网关服务 -> LenderService -> <service name="LenderServiceService">贷方服务
? 第三个端点:贷方网关服务 -> BankingGateway -> <service name="BankingGatewayService">银行网关服务
? 在这里贷方网关服务的出站路由使用了链式路由来将两个出口端点顺序执行:
<outbound> <chaining-router><!-- Sends the message through multiple endpoints using the result of the first invocation as the input for the next. --> <outbound-endpoint synchronous="true" ref="LenderService" /> <outbound-endpoint ref="BankingGateway" transformer-refs="SetLendersAsRecipients ObjectToJMSMessage" /> </chaining-router> </outbound>
?? 也就是贷方网关服务先将消息交给 贷方服务, 贷方服务根据xx额多少将下一步路由到的银行注入消息之中(此时消息自身就含有了下一步路由到哪里去的信息,参见org.mule.example.loanbroker.lender.DefaultLender类),然后就可以称之为根据消息内容的路由 了。消息体LoanBrokerQuoteRequest的Bank[] lenders属性即被注入了下一步的去向银行。
? ok、让我们连成一线!:
?
? 客户发出请求 -> CustomerRequestsREST? -> xx中介服务 -> CreditAgencyGateway -> CreditAgencyGatewayService征信所网关服务 -> LenderGateway -> LenderGatewayService贷方网关服务 -> LenderService -> LenderServiceService贷方服务 -> 银行网关服务 -> 各个银行... -> 银行网关服务 -> reply-to: replyLoanQuotes端点 -> xx中介服务的异步应答器
?
? 除了LenderService是vm其他全是jms、replyLoanQuotes端点是 xx中介服务异步应答器的入站端点、是整个回路的{zh1}一环。
?
10、五家银行使用端点的配置,只是不明白为什么一家银行会配两个端点,比如{dy}家银行会配Bank1和Bank1In两个端点,两个端点地址有什么关系关联?这是我还不明白的...
?
? 再往下就是几个service的配置了,service相当于点、endpoint相当于线,我们已经分析清楚了线以及如何用线连接各个点就基本足够了。至此loanBroker例子就分析完了。