从ActiveMQ原理到实例

来源:互联网 发布:linux端口映射软件 编辑:程序博客网 时间:2024/05/14 02:40

  在介绍activemq之前,先简单介绍JMS,它是J2EE13个规范之一,提供的是消息中间件的规范。

  

  JMS包括以下基本构件:

   连接工厂,是客户用来创建连接的对象,ActiveMQ提供的是ActiveMQConnectionFactory;

   连接connection;

   会话session,是发送和接收消息的上下文,用于创建消息生产者,消息消费者,相比rocketMQ会话session是提供事务性的;

   目的地destination,指定生产消息的目的地和消费消息的来源对象;

   生产者、消费者,由会话创建的对象,顾名思义。


  消息通信机制

   点对点模式,每个消息只有1个消费者,它的目的地称为queue队列;

   发布/订阅模式,每个消息可以有多个消费者,而且订阅一个主题的消费者,只能消费自它订阅之后发布的消息。


  消息确认机制

   Session.AUTO_ACKNOWLEDGE,直接使用receive方法。
   Session.CLIENT_ACKNOWLEDGE,通过消息的acknowledge 方法确认消息。
   Session.DUPS_ACKNOWLEDGE,该选择只是会话迟钝第确认消息的提交。如果JMS provider 失败,那么可能会导致一些重复的消息。如果是重复的消息,那么JMS provider 必须把消息头的JMSRedelivered 字段设置为true。


  原理很多,但是把原理映射在实践中,就更容易懂了。一起看看下面的这个小例子,通过代码回想原理,最后运行显示到控制台上,验证结论。

  新建一个普通Java Project,引进activemq的jar包,build到项目中。新建生产者producer、消费者consumer,如下:

package com.java.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageProducer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;/** * 消息生产者 * @author xing.liu * */public class JMSProducer {private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址private static final int SENDNUM=10; // 发送的消息数量public static void main(String[] args) {ConnectionFactory connectionFactory; // 连接工厂Connection connection = null; // 连接Session session; // 会话 接受或者发送消息的线程Destination destination; // 消息的目的地MessageProducer messageProducer; // 消息生产者// 实例化连接工厂connectionFactory=new ActiveMQConnectionFactory(JMSProducer.USERNAME, JMSProducer.PASSWORD, JMSProducer.BROKEURL);try {connection=connectionFactory.createConnection(); // 通过连接工厂获取连接connection.start(); // 启动连接// 创建Session,第一个参数是开启事务true,第二个参数是消息确认机制属性session=connection.createSession(Boolean.TRUE, Session.AUTO_ACKNOWLEDGE);  destination=session.createQueue("FirstQueue1"); // 创建消息队列messageProducer=session.createProducer(destination); // 创建消息生产者sendMessage(session, messageProducer); // 发送消息session.commit();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally{if(connection!=null){try {connection.close();} catch (JMSException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}/** * 发送消息 * @param session * @param messageProducer * @throws Exception */public static void sendMessage(Session session,MessageProducer messageProducer)throws Exception{for(int i=0;i<JMSProducer.SENDNUM;i++){TextMessage message=session.createTextMessage("ActiveMQ 发送的消息"+i);System.out.println("发送消息:"+"ActiveMQ 发送的消息"+i);messageProducer.send(message);}}}
package com.java.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;/** * 消息消费者 * @author xing.liu * */public class JMSConsumer {private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址public static void main(String[] args) {ConnectionFactory connectionFactory; // 连接工厂Connection connection = null; // 连接Session session; // 会话 接受或者发送消息的线程Destination destination; // 消息的目的地MessageConsumer messageConsumer; // 消息的消费者// 实例化连接工厂connectionFactory=new ActiveMQConnectionFactory(JMSConsumer.USERNAME, JMSConsumer.PASSWORD, JMSConsumer.BROKEURL);try {connection=connectionFactory.createConnection();  // 通过连接工厂获取连接connection.start(); // 启动连接session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 创建Sessiondestination=session.createQueue("FirstQueue1");  // 创建连接的消息队列messageConsumer=session.createConsumer(destination); // 创建消息消费者while(true){TextMessage textMessage=(TextMessage)messageConsumer.receive(100000);if(textMessage!=null){System.out.println("收到的消息:"+textMessage.getText());}else{break;}}} catch (JMSException e) {// TODO Auto-generated catch blocke.printStackTrace();} }}

这个demo是简单的点对点模式下,目的地对象是queue队列,代码中可以看出session.createQueue;从代码中可以联想到上边的原理,也是简而易懂。messageConsumer.receive(100000)这使用的是receive模式,这种模式让消费者consumer不断的问producer要消息,很乱的。

  

  安装了ActiveMQ服务器,在浏览器打开后台监控,地址 http://127.0.0.1:8161/admin/

可以在Queues中看到消息未被消费的条数,已消费的条数。后台监控系统都是一样的,类似rocketMQ,我就不介绍了,多点点就能明白。


  所以生产中我们常用的是监听listener模式,看看下边这个带监听的consumer:

package com.java.activemq;import javax.jms.Connection;import javax.jms.ConnectionFactory;import javax.jms.Destination;import javax.jms.JMSException;import javax.jms.MessageConsumer;import javax.jms.Session;import javax.jms.TextMessage;import org.apache.activemq.ActiveMQConnection;import org.apache.activemq.ActiveMQConnectionFactory;/** * 消息消费者 * @author xing * */public class JMSConsumer2 {private static final String USERNAME=ActiveMQConnection.DEFAULT_USER; // 默认的连接用户名private static final String PASSWORD=ActiveMQConnection.DEFAULT_PASSWORD; // 默认的连接密码private static final String BROKEURL=ActiveMQConnection.DEFAULT_BROKER_URL; // 默认的连接地址public static void main(String[] args) {ConnectionFactory connectionFactory; // 连接工厂Connection connection = null; // 连接Session session; // 会话 接受或者发送消息的线程Destination destination; // 消息的目的地MessageConsumer messageConsumer; // 消息的消费者// 实例化连接工厂connectionFactory=new ActiveMQConnectionFactory(JMSConsumer2.USERNAME, JMSConsumer2.PASSWORD, JMSConsumer2.BROKEURL);try {connection=connectionFactory.createConnection();  // 通过连接工厂获取连接connection.start(); // 启动连接session=connection.createSession(Boolean.FALSE, Session.AUTO_ACKNOWLEDGE); // 创建Sessiondestination=session.createQueue("FirstQueue1");  // 创建连接的消息队列messageConsumer=session.createConsumer(destination); // 创建消息消费者messageConsumer.setMessageListener(new Listener()); // 注册消息监听} catch (JMSException e) {// TODO Auto-generated catch blocke.printStackTrace();} }}
package com.java.activemq;import javax.jms.JMSException;import javax.jms.Message;import javax.jms.MessageListener;import javax.jms.TextMessage;/** * 消息监听 * @author xing * */public class Listener implements MessageListener{@Overridepublic void onMessage(Message message) {try {System.out.println("收到的消息:"+((TextMessage)message).getText());} catch (JMSException e) {e.printStackTrace();}}}

  这种消息监听模式,只是多一个注册消息监听messageConsumer.setMessageListener(new Listener()); 



2 0
原创粉丝点击