Mule的经典实例LoanBroker的学习笔记
最近为了跟上公司发展,要学一下mule。在了解了mule的大概情况之后,便看了看mule的发型包里的一个经典实例LoanBroker,整理一下笔记,若有写得不准确的地方,还望各位大侠不吝赐教。
一 一,安装及部署
1. Jdk。最好1.5版本以上吧,我比较超前,用的1.6.安装完成之后配上环境变量。
2. Mule。我下载的是1.4.4,1.x的差别不是很大,2.x的不太了解。然后配上%MULE_HOME%,把%MULE_HOME%\bin加进path变量中。
3. Maven。Mule的部署支持ant和maven,不过还是推荐maven,ant还是学生时代记忆了。我的maven版本是2.0.7。同样的配置%MAVEN_HOME%,把%MAVEN_HOME%\bin加入环境变量。
二、 二、 一些说明
简单的介绍一下这个应用。
Component |
Description |
Loan Broker Service |
接受用户的LoanRequest 请求(它代表一个用户借款请求), 并且负责聚合返回的LoanQuote(表示单个银行的返回结果)。 |
Credit Agency Service |
检查用户的借款的数额是否符合要求 |
Credit Agency Gateway |
连接总线和CreditAaencyService的纽带 |
Lender Service |
根据用户的信用和申请借款的数额来选择哪些银行接受此次请求。 |
Lender Gateway |
(同上上) |
Banking Gateway |
将loanRequest请求发送到各个指定的银行。 |
这个实例的大概业务流程可以参照mule的官方文档(http://www.mulesource.org/display/MULEINTRO/LoanBroker+ESB),
三、 三、样例演示
1. 在%MULE_HOME%目录打开命令行,输入mvn –Dmaven.test.skip=true,因为单元测试的代码可能通不过编译,所以最好跳过。
2. 编译成功之后,在%MULE_HOME%\examples\loanbroker目录下双击loanbroker.bat文件。
3. 这个LoanBroker提供了多个实现,选择1,回车;
4. 接着mule的服务器就开启了,如果是第一次启动mule的话,会有一堆的license要你来确认,直接回车到底。下面这个页面是关于EJB的配置,直接选1.
5. EJB启动之后,便可以发送借款请求了。在这里选1。然后输入我们的借款请求。
6. 得到了此次异步调用的结果,如果想看看同步调用有什么不一样的话,可以将LoanBrokerApp类中的loanBrokerApp.run(false)改为true。
四、 四、步骤的解析
1. Maven编译部署后的结构图如下:
其中我们只需要关注esb,而bpm和esn我们不去管它。Creditagency是个EJB的工程,可以把它看做一个黑盒,不去管它。重点关注esb和common两个工程。
2. Esb工程中有一个很重要的文件——mule的配置文件loan-broker-esb-mule-config.xml。这个配置文件的配置项无非分为两个部分。一个是mule的model的配置,比如,<mule-descriptor/>它代表了一个UMO组件的配置;另一个就是mule的Transport的配置,包括trasformer,filer,provider的配置。
当程序启动以后,由于我们选择的是1(发送一个标准的借贷请求),所以程序会调用client.dispatch("CustomerRequests", request, null);来发送一个异步请求,其中client是一个MuleClient对象,它可以向MuleServer发送和接受事件对象。request是我们已经封装好的CustomerQuoteRequest对象,也就是我们的消息对象;"CustomerRequests"是事件目的url,系统会根据这个url将事件发送到vm://customer.requests。
3. Mule会把这个事件交给LoanBroker组件来处理,因为它的inbound-router的endpoint配置为vm://customer.requests。那么LoanBroker组件拿到这个事件之后如何来处理这个事件呢?在Mule的官方文档上有这样一句话:
When an event is received for your component Mule dynamically chooses the method to invoke based on the payload type of the event.
也就是说mule会根据事件的payload的种类来选择具体调用的component的方法,在AsynchronousLoanBroker我们找到了这个方法public Object getLoanQuote(CustomerQuoteRequest request) throws LoanBrokerException,而它刚好符合我们的要求。这个方法主要是根据用户的输入生成一个LoanBrokerQuoteRequest对象并返回。
4. 这个方法调用结束之后事件再如何进行呢?在官方文档上又有这一句:
The response or outbound message is obtained using the following -
If the method invoked is not void, (Callable.onEvent() returns an Object) the method return value is used. If null is returned no further processing is done for the current request.
If the method is void, the parameters used to invoke the method are used. This assumes that the parameters themselves were altered or there was no change to the event.
5. 我们这里的方法是有返回值的,所以将方法的返回值作为outbound message。注意此时事件的payload已经为LoanBrokerQuoteRequest了。
6. 注意看LoanBroker的outbound的类型为OutboundPassThroughRouter,它不做任何处理将事件传给endpoint ——CreditAgencyGateway。
7. 事件会根据配置传到CreditAgencyGateway这个component里。这个实现类的实现类为ReflectionMessageBuilder,文档上对这个类的解释为:
Will try and set the result of an invocation as a bean property on the request message using reflection.
也就是说将在这个component会将方法调用的结果设置为消息的一个属性,也就是LoanBrokerQuoteRequest的一个属性。
这里的outbound有两个endpoint,第一个endpoint是发送到一个EJB组件,该组件会根据LoanBrokerQuoteRequest来判断用户的信用程度,并将信用信息以xml字符串的形式返回,然后会调用CreditProfileXmlToCreditProfile这一trasformer来将String类型的对象转换为CreditProfile这一代表用户信用度的对象。结果返回后,将第一个返回结果CreditProfile对象设置为LoanBrokerQuoteRequest的一个属性,然后再将这个LoanBrokerQuoteRequest发送到第二个endpoint——LenderGateway。注意一下第一个endpoint有一个属性remoteSync="true”,它表示component将消息同步发送给第一个endpoint,在结果返回前必须等待,否则发往LenderGateway的事件里LoanBrokerQuoteRequest对象的CreditProfile属性就还没有设置了哦!
8. 事件这一步就到了LenderGateway这个component了(mule是根据endpoint的配置来判断事件的流向,这里只不过名字component的名字和endpoint的名字设置为一样的了),这个component的UMO为BridgeComponent,它会告诉mule它永远不会被调用,只是简单的将inbound-endpoint的输出作为outbound-endpoint的输入,由于它永远不会被调用,所以性能上会表现比较好。
9. 这个component的outbound的类型为ChainingRouter,它往往有多个endpoint,会将上一个endpoint的输出作为下一个endpoint的输入。它首先会通过LenderService,根据用户的信用度和具体的借款额度来选择可以对用户提供借贷的银行列表。根据上面讨论的规则,会调用DefaultLender类的setLenderList方法,由于该方法没有返回值,直接将此LoanBrokerQuoteRequest作为下一个endpoint的输入。第二个endpoint BankingGateway将依次调用SetLendersAsRecipients (下一步将详细表述),ObjectToJMSMessage(将对象转化为JMS消息的格式)。
10. BankingGateway这个component的outbound的类型为StaticRecipientList,它会根据静态配置的endpoint来群发消息,但细细一看配置文件中也没有相关的配置啊!!其实,在上一步调用SetLendersAsRecipients的如下代码:
context.getMessage().setProperty(StaticRecipientList.RECIPIENTS_PROPERTY, recipients);其中recipient为String类型的银行列表。
注意到这个endpoint有个配置<reply-to address="LoanQuotes"/>,它表示每个银行返回的结果都发送到这个endpoint中。
11. 回头去看LoanBroker这个component有个配置如下:
<response-router timeout="1000000">
<endpoint address="LoanQuotes"/>
<router className="org.mule.examples.loanbroker.
routers.BankQuotesResponseAggregator"/>
</response-router>
这个response router的作用其实就是将各个银行返回的结果进行汇总,然后呈现给用户看。