上一篇写了消费者生产者模式,地址http://blog.youkuaiyun.com/kuang_wu/article/details/53260185
使用active之前,先看看java消息模式的基础:http://www.cnblogs.com/chenpi/p/5559349.html
实现点对点消息传输:http://www.cnblogs.com/chenpi/p/5565618.html
实现发布/订阅消息:直接上代码
1、下载activeMq:
官网地址,我下的apache-activemq-5.14.1-bin 地址:http://activemq.apache.org/download.html
运行activeMq: 我的是64位系统 所以进入bin/64/文件夹下运行
运行后输入:http://localhost:8161/admin 进入如下页面。表示运行成功
2、tomcat配置
修改conf/context.xml文件加入如下代码
<Resource auth="Container" brokerName="localhost" brokerURL="failover:(tcp://localhost:61616)?initialReconnectDelay=100&maxReconnectAttempts=5" description="JMS Connection Factory" factory="org.apache.activemq.jndi.JNDIReferenceFactory" name="jms/FailoverConnectionFactory" type="org.apache.activemq.ActiveMQConnectionFactory" useEmbeddedBroker="false"/>
<Resource auth="Container" brokerName="localhost" brokerURL="tcp://localhost:61616" description="JMS Connection Factory" factory="org.apache.activemq.jndi.JNDIReferenceFactory" name="jms/NormalConnectionFactory" type="org.apache.activemq.ActiveMQConnectionFactory" useEmbeddedBroker="false"/>
<Resource auth="Container" factory="org.apache.activemq.jndi.JNDIReferenceFactory" name="jms/topic/MyTopic" physicalName="MY.TEST.FOO" type="org.apache.activemq.command.ActiveMQTopic"/>
<Resource auth="Container" factory="org.apache.activemq.jndi.JNDIReferenceFactory" name="jms/queue/MyQueue" physicalName="MY.TEST.FOO.QUEUE" type="org.apache.activemq.command.ActiveMQQueue"/>
然后activeMq包下的 jar包放入在tomcat/lib包下
3、java代码
新建JMSListener类
package com.flvcd.servlet;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Session;
import javax.jms.Topic;
import javax.jms.TopicSubscriber;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.activemq.ActiveMQConnectionFactory;
/**
*
*
* @version V1.0
*/
public class JMSListener extends HttpServlet implements MessageListener{
public void init(ServletConfig config) throws ServletException{
try {
InitialContext initCtx = new InitialContext();//
Context envContext = (Context) initCtx.lookup("java:comp/env");
ConnectionFactory connectionFactory = (ConnectionFactory) envContext.lookup("jms/FailoverConnectionFactory");
Connection connection = connectionFactory.createConnection();
connection.setClientID("MyClient");
Session jmsSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 普通消息订阅者,无法接收持久消息 //MessageConsumer consumer =
// jmsSession.createConsumer((Destination)
// envContext.lookup("jms/topic/MyTopic"));
// //基于Topic创建持久的消息订阅者,前提:Connection必须指定一个唯一的clientId,当前为MyClient
TopicSubscriber consumer = jmsSession.createDurableSubscriber((Topic)envContext.lookup("jms/topic/MyTopic"), "MySub");
consumer.setMessageListener(this);
connection.start();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
/**
* 接收消息,做对应处理
*/
@Override
public void onMessage(Message message) {
// TODO Auto-generated method stub
if(checkText(message,"RefreshArticleId")!=null){
String articleId = checkText(message,"RefreshArticleId");
System.out.println("接收刷新文章消息,开始刷新文章ID="+articleId);
}else if(checkText(message,"RefreshThreadId")!=null){
String threadId = checkText(message,"RefreshThreadId");
System.out.println("接收刷新论坛帖子消息,开始刷新帖子ID="+threadId);
}else{
System.out.println("接收普通消息,不做任何处理!");
}
}
/**
*
* @Title: checkText
* @return String
* @author zyj
* @throws
*/
private static String checkText(Message m, String s){
try {
return m.getStringProperty(s);
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
}
新建MyPublish类
package com.flvcd.servlet;
import java.io.IOException;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyPublish extends HttpServlet implements MessageListener{
private InitialContext initCtx;
private Context envContext;
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
private MessageProducer producer;
@Override
public void onMessage(Message arg0) {
// TODO Auto-generated method stub
}
public MyPublish() {
super();
}
public void destroy() {
super.destroy(); // Just puts "destroy" string in log
// Put your code here
}
public void init() throws ServletException {
try {
initCtx = new InitialContext();
envContext = (Context) initCtx.lookup("java:comp/env");
connectionFactory = (ConnectionFactory) envContext.lookup("jms/NormalConnectionFactory");
connection = connectionFactory.createConnection();
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer((Destination) envContext.lookup("jms/topic/MyTopic"));
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String content = request.getParameter("content");
try {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
Message testMessage = session.createMessage();
// 发布刷新文章消息
testMessage.setStringProperty("RefreshArticleId",content);
producer.send(testMessage);
// 发布刷新帖子消息
testMessage.clearProperties();
testMessage.setStringProperty("RefreshThreadId", content);
producer.send(testMessage);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
</welcome-file-list>
<servlet>
<servlet-name>sssss</servlet-name>
<servlet-class>com.flvcd.servlet.MyPublish</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>sssss</servlet-name>
<url-pattern>/myPublish.do</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>jms-listener</servlet-name>
<servlet-class>
com.flvcd.servlet.JMSListener
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
index.html
<form action="myPublish.do" method="post">
<input type="text" name="content"/>
<input type="submit" value="提交"/>
</form>
4、运行后打印日志
接收刷新论坛帖子消息,开始刷新帖子ID=asd
5、activieMq对比

Number Of Consumers 消费者 这个是消费者端的消费者数量
Number Of Pending Messages 等待消费的消息 这个是当前未出队列的数量。可以理解为总接收数-总出队列数
Messages Enqueued 进入队列的消息 进入队列的总数量,包括出队列的。 这个数量只增不减
Messages Dequeued 出了队列的消息 可以理解为是消费这消费掉的数量
这个要分两种情况理解
在queues里它和进入队列的总数量相等(因为一个消息只会被成功消费一次),如果暂时不等是因为消费者还没来得及消费。
在 topics里 它因为多消费者从而导致数量会比入队列数高。
简单的理解上面的意思就是
当有一个消息进入这个队列时,等待消费的消息是1,进入队列的消息是1。
当消息消费后,等待消费的消息是0,进入队列的消息是1,出队列的消息是1.
在来一条消息时,等待消费的消息是1,进入队列的消息就是2.
没有消费者时 Pending Messages 和 入队列数量一样
有消费者消费的时候 Pedding会减少 出队列会增加
到最后 就是 入队列和出队列的数量一样多
以此类推,进入队列的消息和出队列的消息是池子,等待消费的消息是水流。