JMS规范是什么
它是JavaEE体系中的一项Message Service
常用消息中间件比较
JMS组成和特点
JMS provider
实现jms接口的消息中间件
JMS Producer 、JMS Constomer
JMS Message 消息头
1)jms destination 消息目的地 队列或者主题
2)jms deviverymode 持久化方式
3)jms expiration 消息过期时间
4)jms 优先级 1到4是普通消息 5-9是加急消息
5)消息id 唯一识别每个消息的标识,是有MQ自己生成
消息头之destination
当然,也可以通过消息进行设置
四种重载:目的地,消息,优先级,存活时间,是否持久化
消息的目的地:队列 和 主题
持久性
消息的过期时间 默认是永不过期的
消息体
发送的消息类型有哪些:
StringMessage MapMessage ByteMessage StringMessage ObjectMessage 五中类型
要求:发送的消息体和接受的消息体要求类型一致。
要求:发送的消息体和接受的消息体要求类型一致。
自定义的消息属性
自定义的消息属性能有什么还用呢 ?
去重、识别、重点标注等
TextMessage textMessage = session.createTextMessage("myTopic……"+ i );
messageProducer.send(textMessage);
textMessage.setStringProperty("自定义消息的key", "自定义消息的value");
如何保证消息的可靠性???
消息的可靠性可以从以下四个方面来回答:
1)消息的持久性
2)消息的事务特性
3)消息的签收机制
4)消息持久化
(队列)消息的持久性
验证1:
设置消息为非持久性,然后生产消息,(服务器不关闭),再去消费消息
消息被正常消费
验证2:
设置消息为非持久性,然后生产消息,(服务器关闭),再去消费消息
生成出的消息
服务器关闭之后,再去消费消息
消息丢失,不能被消费。
刚刚生成的消息被丢失了
验证3:设置消息为持久性,然后生成消息。这个是刚刚生成的消息。
关闭消息服务器,再次重新启动消息,消息依旧存在
去消费消息。消息成功被消费
(topic)消息的持久性
对于topic消息,持久性没有多大意义,因为在topic模式中,需要先启动消费者,然后再启动生产者,如果设置了消息持久性,但是,还没有启动动消费者,则这些消息就会被丢失,不能被消费者消费
设置持久化的topic生成者
package com.ttzz.activemq;
import javax.jms.Connection;
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import org.apache.activemq.ActiveMQConnectionFactory;
public class ActiveMQProduceByTopic {
public static String url = "tcp://localhost:61616";
public static String topicName = "myTopic";
public static void main(String[] args) throws JMSException {
//1.获取工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(url);
//2. 创建连接
Connection connection = activeMQConnectionFactory.createConnection();
//3.创建会话
// 第一个参数 是否开启开启事务
// 第二个参数 是签收模式
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4. 创建目的地 Topic
Topic topic =session.createTopic(topicName);
//5. 创建生产者
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
connection.start();
//6. 发送消息
for (int i = 0; i < 4; i++) {
TextMessage textMessage = session.createTextMessage("myTopic……"+ i );
textMessage.setStringProperty("自定义消息的key", "自定义消息的value");
messageProducer.send(textMessage);
}
//关闭资源
messageProducer.close();
session.close();
connection.close();
System.out.println("OOKK");
}
}
topic 消费者
package com.ttzz.activemq;
import java.io.IOException;
import javax.jms.Connection;
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 javax.jms.Topic;
import javax.jms.TopicSubscriber;
import org.apache.activemq.ActiveMQConnectionFactory;
public class ActiveMQConsumerByTopic {
public static String url = "tcp://localhost:61616";
public static String topicName = "myTopic";
public static void main(String[] args) throws JMSException, IOException {
// 1.获取工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(url);
// 2. 创建连接
Connection connection = activeMQConnectionFactory.createConnection();
connection.setClientID("消费者1");
System.out.println("topic消费者1");
// 3.创建会话
// 第一个参数 是否开启开启事务
// 第二个参数 是签收模式
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
// 4. 创建目的地Topic
Topic topic = session.createTopic(topicName);
// 5. 创建消费者
TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic, "remark..."); // 创建持久化的订阅
connection.start();
Message message = topicSubscriber.receive();
while (message != null) {
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.getText());
message = topicSubscriber.receive();
}
session.close();
connection.close();
System.out.println("OOKK2");
}
}
验证1:启动一个消费者
Active Durable Topic Subscribers :处于激活状态的持久化的topic消费者
Offline Durable Topic Subscribers:处于离线状态的持久化的topic消费者
启动持久化的topic生成者:
topic消费者消费消息
消息服务器
验证2:将消费者1 关闭,启动消费者2
消费者1处于离线状态,启动生成者消费
消费者2能够正常消费消息
再次启动消费者1,消费者1也能正常消费消息
消息的事务特性
事务主要是针对生产者,签收主要针对消费者
//3.创建会话
// 第一个参数 是否开启开启事务
// 第二个参数 是签收模式
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
验证1:
事务设置为 false,执行发送消息,消息自动到服务器
因为设置了消息的持久性,关闭服务器,再次重启启动,该消息依旧存在
验证2:
事务设置为 true,执行发送消息,
看看服务器有没有收到消息。服务器中没有收到刚刚发送的消息。因为没有做消息的提交操作
提交事务
消息入队
事务对于多个消息同时发送,能够保证原子性
session.rollback();
为了验证的需要,需要重启的时候,删除持久化的消息
操作:在配置文件activemq.xml的broker字段添加deleteAllMessagesOnStartup=“true”
可以看到持久化的消息被删除,
生成者开启事务,将消息发送到消息服务器
看到消息
消费者消费掉消息
再次启动一个消费者,发现消息已经被消费,说明消息不能被重新消费
验证2:设置消费者开启事务,但是,没有提交事务【消息被重复消费】。第一次,消费者1正常消费消息,
但是在服务器看到:消息没有被消费
再次启动另一个消费者,发现消息可以被多次消费
一个有趣的现象
生成者以事务的方式将生成者发送到服务器
消费者开启事务进行消费,但是,没有提交事务。保证控制到不灭。再次启动2号消费者,发现不能重复消费???
如果(去掉: System.in.read();)设置消费者4秒之后,没有消息,自动关闭。则启动2号消费者,可以重复消费。
原因呢???哈哈哈哈