ActiveMq(二) - 点对点模式

1、概念

JMS有两种消息通信模型,点对点模型(point to point)(p2p)和发布/订阅模型(pub/sub),ActiveMq实现了JMS接口,同样,ActiveMq也实现了这两种模型。 点对点模型规定了一个消息只能有一个接收者,而发布/订阅模型允许一个消息可以有多个消息接收者

点对点模型

当一个消息生产者产生一个消息时,会把消息放入一个队列(Queue)中,然后消息消费者从Queue中读取消息,如果同时有多个消费者读取消息,ActiveMq保证消息只会被一个消费者读取到,消费者读取到消息之后需要向ActiveMq发送一条确认信息,确认消息已经被接收,此时,队列(Queue)中的消息出队,整个流程就处理完了。

2、几个重要的类

> * ConnectionFactory:工厂类接口,通过这个工厂类接口就可以创建一个与ActiveMq的连接,即Connection。 > * Connection:连接,可以通过这个连接创建会话Session,连接默认是关闭的,需要显式调用Connection的start方法。 > * Session:会话,通过会话类可以创建生产者或消费者、创建队列Queue、创建消息对象。 > * MessageProducer:消息生产者,可将消息发送到队列中。 > * Queue:队列,存放消息的队列。 > * MessageConsumer:消费者,从队列中取出消息。 > * Message:消息接口,常用的实现类是TextMessage和ObjectMessage。

3、三种消息确认机制

> * Session.AUTO_ACKNOWLEDGE:自动确认,当消费接收到消息时,会自动的向ActiveMq发送收到消息确认 > * Session.CLIENT_ACKNOWLEDGE:消费者手动调用Message的acknowledge方法手动确认收到消息。发生在Session层面,当手动调用确认方法时,会把Session中所有已消费的消息都确认 > * Session.DUPS_OK_ACKNOWLEDGE:不必确认已收到消息。但它可能会引起消息的重复接收,但是降低了Session的开销(不需要再去ACKNOWLEDGE一次),所以只有客户端可以重复接收消息时,才可使用此模式

4、生产者代码

``` package com.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class Producer {
public static void main(String[] args) throws JMSException {
//通过tcp协议获取连接工厂
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://server01:61616");

	//通过连接工厂获取连接
	Connection connection = factory.createConnection();
	connection.start();//开启连接
	
	/**
	 * 创建session,此处有两个参数
	 * 	第一个布尔类型的参数表示是否开启事务
	 *  第二个表示消息确认签收模式,此处为自动确认
	 */
	Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
	
	//创建消息队列
	Queue queue = session.createQueue("queue");
	
	//创建消息生产者
	MessageProducer producer = session.createProducer(queue);
    //producer.setDeliveryMode(DeliveryMode.PERSISTENT);
    //DeliveryMode.PERSISTENT:持久化(默认),当ActiveMq关闭时,队列中的消息会保存
    //DeliveryMode.NON_PERSISTENT:非持久化,当ActiveMq关闭时,队列中的消息会丢失
	
	//生产者发送5条消息
	for(int i = 0 ; i < 5; i++){
		Message message = session.createTextMessage("消息" + i);
		producer.send(message);
		TextMessage text = (TextMessage)message;
		System.out.println("生产者发送消息:" + text.getText());
	}
}

}

启动生产者,看到控制台打印出5条记录:

生产者发送消息:消息0
生产者发送消息:消息1
生产者发送消息:消息2
生产者发送消息:消息3
生产者发送消息:消息4

再访问ActiveMq控制台 http://server01:8161,查看Queues中的消息数量
![](https://images2018.cnblogs.com/blog/1373276/201804/1373276-20180415010903949-884323074.png)

此时看到Queues中已经多了5条消息,消费者数量为0
> * Name:队列名称
> * Number Of Pending Messages :等待被处理的消息数量
> * Number Of Consumers :消费者数量
> * Messages Enqueued :入队的消息数量
> * Messages Dequeued:出队的消息数量

<h1>5、消费者代码</h1>

package com.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class Consumer {
public static void main(String[] args) throws JMSException {
//通过tcp协议获取连接工厂
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://server01:61616");

	//通过连接工厂获取连接
	Connection connection = factory.createConnection();
	connection.start();////开启连接
	
	/**
	 * 创建session,此处有两个参数
	 * 	第一个布尔类型的参数表示是否开启事务
	 *  第二个表示消息确认签收模式,此处为自动签收
	 */
	Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
	
	//创建消息队列
	Queue queue = session.createQueue("queue");
	
	//创建消费者
	MessageConsumer consumer = session.createConsumer(queue);
	
	while(true){
		Message message = consumer.receive();
		if(message == null){
			break;
		}
		TextMessage textMessage = (TextMessage)message;
		System.out.println("消费者收到消息:" + textMessage.getText());
	}
}

}

启动消费者,看到Eclipse控制台收到5条记录,说明此时消费者已经收到消息了。

消费者收到消息:消息0
消费者收到消息:消息1
消费者收到消息:消息2
消费者收到消息:消息3
消费者收到消息:消息4


此时再看看ActiveMq控制台,待消费的消息数量已经为0,已经有一个消费者了,出队的消息数量也是5,说明消费者已经向ActiveMq发送确认收到消息的通知了,队列中的消息已经被消费完了。此时若再次启动消费者,Eclipse控制台不会再打印消息。
![](https://images2018.cnblogs.com/blog/1373276/201804/1373276-20180415012048914-1223879859.png)

<h1>6、消费者监听模式</h1>
消费者接收消息有两个方法,上面讲的方式一是调用receive方法来接收,第二种方式是注册监听器的方式来获取消息。
创建两个消费者,分别监听在Queue上,当消费者产生消息放入Queue中时,两个消费者都会去接收消息,但是ActiveMq会保证一个消息只有一个消费者能收到。

package com.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class ConsumerListener {
public static void main(String[] args) throws JMSException {
//通过tcp协议获取连接工厂
ConnectionFactory factory = new ActiveMQConnectionFactory("tcp://server01:61616");

	//通过连接工厂获取连接
	Connection connection = factory.createConnection();
	connection.start();////开启连接
	
	/**
	 * 创建session,此处有两个参数
	 * 	第一个布尔类型的参数表示是否开启事务
	 *  第二个表示消息确认签收模式,此处为自动签收
	 */
	Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
	
	//创建消息队列
	Queue queue = session.createQueue("queue");
	
	//创建消费者
	MessageConsumer consumer = session.createConsumer(queue);

	//监听模式
	consumer.setMessageListener(new MessageListener() {
		
		public void onMessage(Message message) {
			TextMessage textMessage = (TextMessage)message;
			try {
				System.out.println("消费者一收到消息:" + textMessage.getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
	});
	
	MessageConsumer consumer1 = session.createConsumer(queue);
	consumer1.setMessageListener(new MessageListener() {
		public void onMessage(Message message) {
			TextMessage textMessage = (TextMessage)message;
			try {
				System.out.println("消费者二收到消息:" + textMessage.getText());
			} catch (JMSException e) {
				e.printStackTrace();
			}
		}
	});
}

}

先启动消费者程序,此时会看到ActiveMq控制台已经存在两个消费者了,但是还没有消息。
![](https://images2018.cnblogs.com/blog/1373276/201804/1373276-20180415013155244-1046460892.png)

再启动生产者,会看到Eclipse控制台打印出5条记录,表明5个消息分别被不同的消费者接收到了,也就是同一个消息只能被一个消费者接收

消费者一收到消息:消息0
消费者二收到消息:消息1
消费者一收到消息:消息2
消费者二收到消息:消息3
消费者一收到消息:消息4

此时再看一下ActiveMq控制台,待处理的消息已经为0,入队和出队的消息记录都是5。
![](https://images2018.cnblogs.com/blog/1373276/201804/1373276-20180415013445828-567862121.png)
posted @ 2018-04-15 01:38  风中的蜗牛  阅读(1498)  评论(0编辑  收藏  举报