前言
本章讲解ActiveMQ的发布订阅模式,也就是PS(publish/subscribe)模型
方法
1.概念
我们之前说过ActiveMQ的PTP模式,也就是点对点模式。
而PS模式,是生产者将消息发布到Topic中,同时有多个消费者订阅(消费)该消息。和PTP模式不同的是,发布到Topic的消息会被所有的消费者消费。当生产者发布消息,不管是否有消费者,都不会保存消息。
2.使用Java实现PS模式
1)编写生产者代码
package cn.edu.ccut.test;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
/**
* 测试主动消费
* 生产者代码
* @author jwang
*
*/
public class topic_producer {
/**
* 发送消息到ActiveMQ中,具体的消息内容为参数信息
* 开发JMS相关代码过程中,使用的接口都是javax.jms包下的类型
* @param datas - 消息内容
*/
public void sendMessage(String datas){
//连接工厂
ConnectionFactory factory = null;
//连接
Connection connection = null;
//目的地
Destination destination = null;
//会话
Session session = null;
//消息发送者
MessageProducer producer = null;
//消息对象
Message message = null;
try {
//常见连接工厂,连接ActiveMQ服务的连接工厂
//创建工厂,构造方法有三个参数,分别是用户名,密码,连接地址
//无参构造,有默认的链接地址。本地连接。localhost
//单参数构造,无验证模式的。没有用户的认证
//三参数构造,有认证+指定地址
factory = new ActiveMQConnectionFactory("admin", "admin",
"tcp://192.168.1.103:61616");
//创建工厂,创建连接对象
//创建连接的方法有重载,其中有createConnection(String username,String password);
connection = factory.createConnection();
//建议启动连接,消息的发送者不是必须启动连接,消息的消费者必须启动连接
//producer在发送消息的时候,会检查是否启动了连接。如果未启动,自动启动
//如果有特殊的配置,建议配置完毕后再启动连接
connection.start();
//通过连接对象,创建会话对象。
/**
* 创建会话的时候,必须传递两个参数,分别代表是否支持事务和如何确认消息处理。
* transacted - 是否支持事务,数据类型是boolean。true - 支持,false - 不支持
* true - 支持事务,第二个参数对producer来说默认无效。建议传递的数据是Session.SESSION_TRANSACTED
* false - 不支持事务,常用参数。第二个参数必须传递,且必须有效。
*
* acknoowledgeMode - 如何确认消息的处理,使用确认机制实现的。
* AUTO_ACKNOWLEDGE - 自动确认消息。消息的消费者处理消息后,自动确认。常用。
* CLIENT_ACKNOWLEDGE - 客户端手动确认。消息的处理者消费后,必须手工确认。
* DUPS_OK_ACKNOWLEDGE - 有副本的客户端手动确认
* 一个消息可以多次处理
* 可以降低Session的消耗,在可以容忍重复消息时使用。(不推荐使用)
*/
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//创建目的地。参数是目的地名称,是目的地的唯一标记
destination = session.createTopic("test-topic");
//创建会话对象,创建消息的发送者producer
//创建的消息发送者,发送消息一定到指定的目的地中。
producer = session.createProducer(destination);
//创建文本消息对象,作为具体数据内容的载体.
message = session.createTextMessage(datas);
//使用producer,发送消息到ActiveMQ中的目的地。如果消息发送失败。抛出异常。
producer.send(message);
System.out.println("消息已发送");
} catch (Exception e) {
e.printStackTrace();
} finally {
//回收资源
if(producer != null){ //回收消息发送者
try {
producer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(session != null){ //回收会话对象
try {
session.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(connection != null){ //回收连接对象
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
@Test
public void testProducer(){
topic_producer producer = new topic_producer();
producer.sendMessage("Topic-ActiveMQ!");
}
}
2)编写消费者代码
package cn.edu.ccut.test;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.junit.Test;
/**
* 测试主动消费
* 消费者代码
* @author jwang
*
*/
public class topic_consumer {
public String receiveTextMessage(){
String result = "";
ConnectionFactory factory = null;
Connection connection = null;
Destination destination = null;
Session session = null;
//消息的消费者,用于接收消息的对象。
MessageConsumer consumer = null;
Message message = null;
try {
factory = new ActiveMQConnectionFactory("admin", "admin",
"tcp://192.168.1.103:61616");
connection = factory.createConnection();
//消费者必须启动连接,否则无法处理消息
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createTopic("test-topic");
//创建消息的消费者。在指定的目的地中获取消息
consumer = session.createConsumer(destination);
//获取消息队列中的消息.receive方法是一个主动获取消息的方法,执行一次拉取一个消息。开发少用。
message = consumer.receive();
//处理文本消息
result = ((TextMessage)message).getText();
} catch (Exception e) {
e.printStackTrace();
} finally {
//回收资源
if(consumer != null){ //回收消息消费者
try {
consumer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(session != null){ //回收会话对象
try {
session.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if(connection != null){ //回收连接对象
try {
connection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return result;
}
@Test
public void testConsumer(){
topic_consumer consumer = new topic_consumer();
String message = consumer.receiveTextMessage();
System.out.println("消息内容是:"+message);
}
}
我们先运行一下管理界面查看队列状态:
这里此刻只有我们测试PTP模式时的两个队列。
我们首先运行一下消费者代码订阅:
我们发现,此时它正在等待消息生产者发送消息。
我们这个时候看一下队列的状态,可以发现有topic存在,名字为test-topic
我们尝试运行生产者代码发送消息:
可以发现,发送的内容被订阅了。也就是成功的就收到了消息。
这个时候我们在观察队列: