分析对象:
Spring-Integration-Sample-jms
common.xml, inbound-Gateway.xml, outbound-Gateway.xml, DemoBean.java, GatewayDemo.java
一、让例子跑起来 make it run!
运行GatewayDemo。将通过Broker方式启动ActiveMQ, 如果将common.xml中brokerURL修改为tcp://localhost:61616, 则可使用外置的Standalone ActiveMQ服务器。
启动后,在控制台输入任意字符后回车,控制台将返回你输入字母的大写字母。
二、分析, how it works?
根据配置文件,可以将消息的路由绘制如下:
<stream:stdin-channel-adapter> 是一个管道适配器,将不同类型的管道进行连接。把System.in这个输入转换到stdinToJmsoutChannel这个管道中。
<jms:outbound-gateway> 标签定义了一个写消息网关(这里outbound是从Application到JMS),会将输入管道中的数据发送到JMS Queue中(requestQueue);
<jms:inbound-gateway> 标签定义了一个读消息网关(从JMS Queue到Application代码),从requestQueue中将消息读出来之后写入demoChannel1管道。
通过demoChannel1管道,将信息发送给一个<service-activator>,这是一个通用意义的Message Endpoint, 是对消息进行处理的关键点。调用demoBean这个Spring Bean的upperCase方法。(可能有人找不到什么地方定义了demoBean,是因为这个Bean定义是隐含的,通过<context:component-scan base-package="org.springframework.integration.samples.jms"/>自动引入的,为什么执行demoBean.upperCase方法,是因为DemoBean.upperCase这个方法具有@ServiceActivator标签)
upperCase返回的结果会被写入到jmsReplyToStdoutChannel这个管道中。(这是在outbound gateway中定义的,向queue写入消息时就在Message的Header中添加上了对应的信息,在<service-activator>中如果没有显式地定义replyChannel,就会根据Message Header中的返回地址去找。)
最终通过stdout这个<stream:stdout-channel-adapter>将jmsReplyTostdoutChannel管道中的消息进行转换,输出到System.out中。
三、Hack into
如果我们不从控制台输入信息,是否也能执行呢?我们通过一个代码向stdinToJmsoutChannel管道写入一个信息,然后就可以在控制台获得一个输出。
通过应用代码操作JMS,当然最好是通过Gateway了。我们定义一个接口:
package org.springframework.integration.samples.jms; import org.springframework.integration.annotation.Gateway; public interface MyGateway { @Gateway(requestChannel="stdinToJmsoutChannel") public void upperCase(String input); }
注意@Gateway Annotation, 其requestChannel定义为原来stdin适配器的管道stdinToJmsoutChannel.
然后在common.xml中定义对应的<integration:gateway id="myGateway" service-interface="xxx.xxx.xxxx.MyGateway" />。
最后,只需要在main方法中进行调用就可以了。
MyGateway gateway = (MyGateway)context.getBean("myGateway"); gateway.upperCase("hello");
停!
MyGateway只是一个接口,能直接执行吗? 呵呵,是可以的,原因参见我的另外一个文章《接口能直接运行吗?》
再次运行,这回是不是不用在控制台输入,就可以获得一个输出了?