是什么
JMS是Java EE中的一部分,好比是盘子和点心的关系,JMS是Java EE中的额一个组成部分。
JMS的组成
JMS有四部分组成。分别为:
JMS privider: 实现JMS接口与规范的消息中间件,也就是我们的MQ服务器。
JMS producer:消息生产者,创建与发送JMS消息的客户端应用。
JMS consumer:消息的消费者,接受与处理JMS消息的客户端应用。
JMS message:JMS的消息。
JMS message的组成
JMS message由三部分组成:消息头、消息头和消息属性。
消息头
在JMS message中包含很多消息头,如下所示:
几个比较重要的消息头如下:
1、JMSdestination:message发送的目的地,比如queue和topic。
2、JMSDeliveryMode:主要是指定消息的持久或者非持久化。
3、JMSExpiration:消息存活时间。
4、JMSPriority:消息优先级。
5、JMSMessageID:唯一识别每个消息的标志,由MQ产生。
消息体
消息体顾名思义作用就是封装具体消息的数据。
那么消息的数据到底有多少种格式呢,有五种。其中最常用的为TextMessage和MapMessage两种。
1、TextMessage:普通的字符串消息,包含一个string。
2、MapMessage:一个map类型的消息,key为stirng类型,而value 为java的基本类型。如下:
如果MapMessage中的value放的是char类型数据,则创键方式如下所示:
3、BytesMessage:二进制数组消息,包含一个byte[]。
4、StreamMessage:java数据流消息,用标准流操作来顺序的填充或读取。
5、ObjectMessage:对象消息,包含一个可序列化的java对象。
注意:
发送和接受的消息体类型必须是一致对应的。如发送的是TextMessage,则接收方式如下:
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if (null != message && message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("msg-----" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
消息属性
如果需要使用消息头以外的值,那么可以使用消息属性(一种加强型的api),可用于识别/去重/重点标注等操作。
JMS的可靠性
persistent:持久性
基于队列queue
1、非持久化:
2、持久化
3、默认情况下ActiveMQ是持久化的,即向MQ中发送消息之后即使MQ服务器宕机挂掉然后重新启动之后,消费者也可以从MQ中取到原来发送的消息;而如果使用上述方法设置消息非持久化,那么在重新启动之后就不能取到原来的数据,原来的数据就会被丢失。
基于主题topic发布订阅
持久的发布主题生产者:
package com.atguigu.durable;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
/**
* ActiveMQ
* JMS(Java Message Service)的生产者编码
* @author xxy
* @date 2019/12/16
*/
public class DurableJmsProduceTopic {
private static final String ACTIVE_URL = "tcp://192.168.0.119:61616";
private static final String TOPIC_NAME = "topic-01";
public static void main(String[] args) throws JMSException {
//创建连接工厂,按照指定的url地址,采用默认用户名和密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVE_URL);
//通过连接工厂创建连接
Connection connection = activeMQConnectionFactory.createConnection();
//创建回话session,两个参数:事务和签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//常见目的地(队列或queue者主题topic)
Topic topic = session.createTopic(TOPIC_NAME);
//创建生产者
MessageProducer producer = session.createProducer(topic);
//设置持久化的topic生产者
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
connection.start();
//使用MessageProducer生产3条消息发送到MQ的队列里
for (int i = 0; i < 3; i++) {
//创建消息
TextMessage textMessage = session.createTextMessage("msg------" + i);
//通过生产者MessageProducer发送给MQ
producer.send(textMessage);
}
//关闭资源
producer.close();
session.close();
connection.close();
}
}
持久的发布主题消费者:
package com.atguigu.durable;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;
/**
* ActiveMQ
* JMS(Java Message Service)的生产者编码
* @author xxy
* @date 2019/12/16
*/
public class DurableJmsConsumerTopic {
private static final String ACTIVEMQ_URL = "tcp://192.168.0.119:61616";
private static final String TOPIC_NAME = "topic-01";
public static void main(String[] args) throws JMSException, IOException {
System.out.println("订阅者z3");
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
Connection connection = factory.createConnection();
connection.setClientID("z3");
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(TOPIC_NAME);
TopicSubscriber durableSubscriber = session.createDurableSubscriber(topic, "remark..");
connection.start();
Message message = durableSubscriber.receive();
while (null != message) {
TextMessage textMessage = (TextMessage) message;
System.out.println(textMessage.getText());
message = durableSubscriber.receive();
}
session.close();
connection.close();
}
}
持久化的表现:
持久性的订阅者首先启动进行订阅,就算中途离线关掉了系统,也会在下次连接上线后收到消息。
transaction:事务
无论是在生产者还是消费者的时候都要创建一个session会话,如下
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
其中第一个参数就是事务,false代表关闭事务,true代表使用事务。
如果生产者和消费者都设置为false,那么在producer.send(message)之后,消息就会直接传到队列中,consumer.receive之后消息就会直接取出来;
如果生产者和消费者都设置为true,那么必须手动session.commit()进行提交,出错之候可以session.rollback()。如果不commit,那么:producer.send()之后,消息不会发送到消息队列中,并且因为没有commit,consumer.receive()会多次消费同一条消息。
acknowledge 签收模式
签收模式的效果如何与事务的开启与否有着密切的关系,主要常用的签收模式包括两种:自动签收AUTO_ACKNOWLEDGE和手动签收CLIENT_ACKNOWLEDGE。
1、在事务为false的时候,签收模式为:AUTO_ACKNOWLEDGE
在此模式下,为自动签收。不用任何操作就会签收,不会出现二次消费的情况
2、在事务为false的时候,签收模式为:CLIENT_ACKNOWLEDGE
在此模式下消息不会自动签收,必须使用message.acknowledge()手动对消息进行签收,否则会出现二次消费。
3、在事务为true的时候,签收模式为:AUTO_ACKNOWLEDGE
在此模式下,并且调用session.commit()进行事务提交的情况下为自动签收。若事务不提交,则会出现二次消费的情况。
4、在事务为true的时候,签收模式为:CLIENT_ACKNOWLEDGE
在此模式下,并且调用session.commit()进行事务提交的情况下为手动签收。若事务不提交,则会出现二次消费的情况。即使message.acknowledge()进行消息手动签收也会出现二次消费。
总结:
在事务关闭的情况下,消息是否自动签收取决于签收模式,如AUTO_ACKNOWLEDGE或者CLIENT_ACKNOWLEDGE;在事务开启的情况下,并且调用commit方法,则无论签收模式是什么都会自动提交,在事务开启的情况下,若不调用commit方法,则无论签收模式是什么都不会自动提交。
总结
JMS点对点模式总结
JMS发布订阅模式总结
非持久订阅
持久订阅
用哪个
当所有消息必须被接受,则用持久订阅。当丢失消息能够被容忍,则用非持久订阅。
来源:CSDN
作者:youngyang的博客
链接:https://blog.csdn.net/qq_42013590/article/details/103586950