ActiveMQ 使用Ajax 收发消息实战
1. 原理简析
ActiveMQ 在版本发布包中包含了web sample的demo,其中就包含js与ActiveMQ交互的库文件amq.js.
以5.8.0版本为例,该文件目录为
apache-activemq-5.8.0\webapps-demo\demo\js\amq.js这个js文件还依赖一些基于公共JavaScript框架的
适配器文件,比如依赖jQuery的适配器为amq_jquery_adapter.js. 因此,使用amq.js时,必须先引入
jquery库文件和适配器库文件amq_jquery_adapter.js,然后在引入amq.js.
amq.js里面提供了sendMessage方法可以发送消息到代理,而addListener和removeListener方法可以给
指定的的消息目的地添加或删除监听器,添加监听器后即可接收消息了.
在web页面使用sendMessage发送消息,其实是向后台的一个servlet发送请求,然后由该servlet发送消息给代理.
这个servlet的类由ActiveMQ提供(后面配置web.xml时介绍)
页面调用addListener注册监听器,其实也是发送请求给servlet,由servlet创建一个目的地的消费者,当该目的地
有消息时,servlet处理消息,并将消息处理响应发送给客户端.因为采用web的CS架构,servlet不能直接将响应发送
给客户端. 这里amq.js中其实是采用了一种页面轮询的方式向服务器请求消息,以便监听代理上指定的目的地.
详细信息参考ActiveMQ文档:http://activemq.apache.org/ajax.html
简而言之就是,
发送消息: amq.js使用sendMessage发送消息给servlet,servlet在将消息发给代理.
接收消息: amq.js使用addListener注册监听器接收并处理消息,其实也是发送请求给servlet,servlet产生消息消费者
消费指定目的地的消息并产生客户端响应,amq.js使用一种特殊的轮询机制不断从服务器获取消息处理的响应.
2.相关配置
本示例使用tomcat 5作为容器,使用Maven管理工程.
首先使用Maven插件建立一个web工程.
涉及到的配置文件有两个 web.xml和pom.xml.
2.1 web.xml配置,主要是配置接收客户端请求的servlet
<servlet> <servlet-name>AjaxServlet</servlet-name> <servlet-class>org.apache.activemq.web.AjaxServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>AjaxServlet</servlet-name> <url-pattern>/amq/*</url-pattern> </servlet-mapping>
注意这里的<url-pattern>/amq/*</url-pattern>,配置会在amq.js发送消息时请求的servlet的rul,
在amq.js初始化时要做响应的配置.
上面<load-on-startup>1</load-on-startup>表示这个servlet在tomcat启动时就实例化,由前面远离
简析可知,这个servlet是要连接到实际的代理的,所以web.xml还提供了一个参数,用来配置这个servlet
要连接代理的URI,配置如下,表示启动时servlet将连接tcp://127.0.0.1:61616.
这里使用tcp://127.0.0.1:61616时,假如中途代理关闭了是不能自动重连的,可以使用
failover协议,在代理从失败中恢复时可以重连(URI使用failover://(tcp://127.0.0.1:61616)?randomize=false)
<context-param> <param-name>org.apache.activemq.brokerURL</param-name> <param-value>tcp://127.0.0.1:61616</param-value> <description>The URL of the Message Broker to connect to</description> </context-param>
下面的配置表明 不需要启用一个嵌入式代理
<context-param> <param-name>org.apache.activemq.embeddedBroker</param-name> <param-value>false</param-value> <description>Whether we should include an embedded broker or not</description> </context-param>
下面的配置是因为,
因为ajax+activemq需要servlet3.0的支持,而servlet3.0又只有在tomcat7中得到支持,
所有加上jetty此包,就能在tomcat5,tomcat6运行了。
(参考: http://blog.csdn.net/gongminrui8987/article/details/9446275
另,http://blog.csdn.net/goodbaby728/article/details/8853072)
注意,这里使用tomcat5必须要有下面的配置,否则不能接收消息,服务器报500错误.
<filter> <filter-name>session</filter-name> <filter-class>org.eclipse.jetty.continuation.ContinuationFilter</filter-class> </filter> <filter-mapping> <filter-name>session</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.2 pom.xml配置
这个文件注意是配置依赖到的jar包.
注意配置下面两个即可:
<dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-all</artifactId> <version>5.8.0</version> </dependency> <dependency> <groupId>org.apache.activemq</groupId> <artifactId>activemq-web</artifactId> <version>5.8.0</version> </dependency>
3. amq.js的使用
在index.jsp里面点击send按钮发送消息给主题:topic://TEST,并注册这个主题的监听器.
需要注意的地方:'
(1) 需要引入三个js
<script type="text/javascript" src="js/jquery-1.4.2.min.js"></script> <script type="text/javascript" src="js/amq_jquery_adapter.js"></script> <script type="text/javascript" src="js/amq.js"></script>
(2)amq.js需要初始化
<script type="text/javascript"> $(document).ready( function() { org.activemq.Amq.init( { uri: 'amq', logging: true, timeout: 1, clientId:(new Date()).getTime().toString() } ); }); </script>
上面的url就是web.xml中配置的请求URL.其他的参数含有,可以看amq.js代码中的注释.
clientId是为了在一个浏览器的多个页面中使用ActiveMQ Ajax.
详情参考 http://activemq.apache.org/ajax.html
页面的Using AMQ Ajax in Multiple Browser Windows 部分
(3) 发送消息
首先,消息的格式是格式良好的xml格式
var msg = "<msg type='common'>" + "<id>msg1</id>" + "<content>This is test content</content>" + "</msg>";
调用发送消息方法,点击按钮时,发送消息
$("#send").click( function() { amq.sendMessage("topic://TEST", msg); });
(4) 接收消息
首先,定义消息处理器:
var myHandler = { rcvMessage: function(message) { alert(message.getAttribute('type')); //console.log(message); } };
然后注册消息处理器:
amq.addListener("testHandlerId","topic://TEST",myHandler.rcvMessage);
上面的第一个参数是处理器id,可以通过将这个ID传递给removeListener来取消注册.
注意,消息处理器中的message参数貌似是一个xml文档格式.
使用message.getAttribute('type')这样可以获取属性值.
详细方法可以参考 ActiveMQ 版本中的chat例子.
4. 扩展
(1)使用ActiveMQ的Ajax特性可以作为一种实现服务器推送消息到客户端的处理方式.
(2)采用两个消息目的地 Destination_Request和Destination_Response 可以实现请求 应答程序
代理Broker_A 和 Broker_B互联,servlet 连接到 Broker_A,
页面发送消息给Destination_Request,页面监听Destination_Response.
同时有另一个系统,连接到Broker_B监听Destination_Request,收到消息后处理消息,将消息处理
结果发送给Destination_Response.
5. 遗留问题
本例在Chrome 版本 32.0.1700.76 m 运行,发送消息时,控制台报错:
Refused to set unsafe header "Connection" amq_jquery_adapter.js:77
request.beforeSend amq_jquery_adapter.js:77
c.extend.ajax jquery-1.4.2.min.js:128
org.activemq.AmqAdapter.ajax amq_jquery_adapter.js:82
sendJmsMessage amq.js:183
sendMessage amq.js:276
(anonymous function) (index):67
c.event.handle jquery-1.4.2.min.js:55
j.handle.o
因为这个错,不影响功能实现,这里选择忽略.
注:附件工程中org.apache.activemq.web.AjaxServlet
和org.apache.activemq.web.MessageListenerServlet
来自ActiveMQ-web包,拷贝到这里便于跟代码调试.
Maven版本及教程参考: http://jackyin5918.iteye.com/blog/1945203
myeclipse安装Maven插件参考: http://jackyin5918.iteye.com/blog/1945929