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)