ActiveMQ认识和深入(二),发布/订阅、事务、签收

ActiveMQ认识和深入(二),发布/订阅、事务、签收

JMS是什么?


什么是JAVA消息服务? 百度百科:(https://baike.baidu.com/item/JMS/2836691)

是Java平台上有关面向消息中间件(MOM)的技术规范,JAVA消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息提供了一组通用的接口,包括创建,发送读取消息等,用于支持JAVA应用程序开发。在JAVAEE中,当两个应用程序使用JMS进行通信时,它们之间并不是直接相连的,而是通过一个共同的消息收发服务组件关联起来以达到解耦、异步、削峰的效果

MQ中间件的其他产品


在这里插入图片描述

在这里插入图片描述

JMS的组成结构和特点


JMS provider


实现JMS接口和规范的消息中间件,也就是MQ的服务;

JMS producer


消息生产者,创建和发送JMS消息的客户端应用;

JMS consumer


消息消费者,接收和处理JMS消息的客户端应用;

JMS message


在这里插入图片描述
在这里插入图片描述

消息头

JMSDesitination :发送的目的地,主要是指QueueTopic;

JMSDeliveryMode:持久模式和非持久模式。一条持久性的消息,应该被传送“一次仅仅一次”,这就意味者如果JMS提供者出现故障,该消息不会丢失,它会在服务器恢复之后再次传递。一条非持久性的消息,最多会传送一次,这意味者服务器出现故障,该消息永久丢失。

JMSExpiration:可以设置消息在一定时间后过期,默认是永不过期,消息过期时间,等于Destinationsend 方法中的timeToLive值加上发送时刻的GMT的时间值,如果timeToLive 值等于零,则JMSExpriration被设为零,表示该消息永不过期。如果发送后,在消息过期时间之后还没有被发送到目的地,则该消息被清楚。

JMSPriority:消息优先级, 从0-9十个级别,0到4是普通消息,5-9是加急消息。JMS不要求MQ严格按照这十个优先级发送消息,但必须保证加急消息要优于普通消息到达。默认是4级。

JMSMessageID:唯一识别每个消息的标识由MQ产生。

消息体

封装具体的消息数据

5种消息体格式

在这里插入图片描述

  • TextMessage:普通字符串消息,包含一个String

  • MapMessage:一个Map类型的消息,KeyString类型,而值为JAVA的基本类型;

  • BytesMessage:二进制数组消息,包含一个Byte[]

  • StreamMessageJava数据流消息,用标准流操作来顺序的填充和读取;

  • ObjectMessage:对象消息,包含一个可序列化的Java对象;

发送和接受的消息体类型必须一致对应

消息属性

它们是以属性名和属性值对的形式指定的。可以将属性是为消息头得扩展,属性指定一些消息头没有包括的附加消息,比如可以在属性里指定消息选择器。

消息的属性就像可以分配给一条消息的附加消息头一样。它们允许开发者添加有关消息的不透明附加消息。它们还用于暴露消息选择器在消息过滤器时使用的数据。

TextMessage textMessage = session.createTextMessage();
textMessage.setText(text);
//自定义属性
textMessage.setStringProperty("username","张三");
  • 如果需要除消息字段以外的值,那么可以使用消息属性;

  • 识别 / 去重标注等操作非常有用的方法;

JMS的可靠性


持久化


持久化,当服务器宕机,消息依然存在。

messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);

Queue 队列 和 Topic ,默认持久化;

持久化消息:这是队列的默认传送模式此模式保证只被传送一次和成功使用一次。对于这些消息,可靠性是优先考虑的因素。可靠性的另一个重要方面是确保持久性消息传送至目标后,消息服务在向消费者传送它们之前不会丢失这些消息。

源码

选择 ActionMQSession

在这里插入图片描述

查看方法 createProducer() ;

在这里插入图片描述

源码 116行, 默认参数 是2 ,持久化。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

持久化的Topic 发布和订阅


package com.kelecc.activemq.topic;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;
import java.io.IOException;

/**
 * 功能描述: 发布和订阅
 *
 * @author: keLeCc
 */
public class JmsConSumerTopic {
    private static final String ACTIVEMQ_URL = "tcp://localhost:61616";
    private static final String TOPIC_NAME = "topic01";

    public static void main(String[] args) throws JMSException, IOException {
        System.out.println("张三开始订阅消息");
        //创建连接工厂,安装给定的url地址,采用默认用户名密码;
        ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //通过连接工厂,获得连接并启动访问;
        Connection factoryConnection = factory.createConnection ();
        factoryConnection.setClientID("张三");
        factoryConnection.start();

        //创建会话, 事务不开启,自动签收
        Session session = factoryConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //创建目的地主题
        Topic topic = (Topic) session.createTopic(TOPIC_NAME);
        TopicSubscriber durableSubscriber = session.createDurableSubscriber(topic, "remake....");
        factoryConnection.start();

        //订阅消息
        Message messages = durableSubscriber.receive();

       while (null != messages){
           TextMessage textMessage = (TextMessage) messages;
           System.out.println("=====消费者接收到消息=====" + textMessage.getText());
           messages = durableSubscriber.receive(3000L);
       }
        //保持控制台,因为监听需要时间,所以这里不写,会存在消息没有消费到
        session.close();
        factoryConnection.close();
    }

}

在这里插入图片描述

  • 一定要先运行一次消费者,等于向MQ注册,类似我关注了某个微信公众号;
  • 然后再运行生成者发送消息;
  • 无论消费者是否在线,都会接收到,不在线的话,下次连接的时候,会把没有收过的消息都接收下来;

非持久化


非持久化,当服务器宕机,消息不存在。

messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);

事务


生产者事务


如果设置事务为true,需要先send在执行commit,消息才被真正的提交到队列中。消息需要批量发送,需要缓冲区处理。后面的签收参数已经没有什么效果。事务的优先级更高。

Session createSession(boolean transacted, int acknowledgeMode) throws JMSException;
 session.commit();

如果设置事务为false,只要执行send,就进入队列中。关闭事务,那第2个签收参数的设置需要有效。

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

消费者事务


如果设置事务为true,需要先receive()最后执行commit,消息才被真正的被消费。不然消息会被重复消费。

Session createSession(boolean transacted, int acknowledgeMode) throws JMSException;
 session.commit();

如果设置事务为false,只要执行receive(),就直接被消费。

Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

签收(针对消费者)


四种签收方式


在这里插入图片描述

  • AUTO_ACKNOWLEDGE(默认):自动签收;

  • CLIENT_ACKNOWLEDGE:手动签收;

//非事务签收
Session session = factoryConnection.createSession(false, Session.CLIENT_ACKNOWLEDGE);

TextMessage textMessage = (TextMessage) messages;
System.out.println("=====消费者接收到消息=====" + textMessage.getText());
//消费者客户端调用 acknowledge(); 手动签收
textMessage.acknowledge();

//事务签收
Session session = factoryConnection.createSession(true, Session.CLIENT_ACKNOWLEDGE);

TextMessage textMessage = (TextMessage) messages;
System.out.println("=====消费者接收到消息=====" + textMessage.getText());
// 这里可以不用手动签收,设置了事务,后面的签收会变成自动签收,事务的优先级更高
//textMessage.acknowledge();
session.commit();
  • DUPS_OK_ACKNOWLEDGE:可以允许部分重复的签收;

  • SESSION_TRANSACTED:事务级签收;

JMS的点对点


点对点模型是基于队列的,生成者发送消息到队列,消费者从队列接收消息,队列的存在使得消息的异步传输成为可能。和我们平时给朋友发送短信类型

1.如果在Session 关闭时有部分消息已被收到但还没有被签收(acknowledged),那当消费者下次连接到相同的队列时,这些消息还会被再次签收。

2.队列可以长久地保存消息直到消费者接收到消息。消费者不需要担心消息会丢失而时刻和队列保持激活的连接转态,充分体现了异步传输模式的优势。

JMS的发布订阅


JMS Pub/Sub 模型定义了如何向一个内容节点发布和订阅消息,这些节点被称为 topic;

主题可以被认为是消息的传输中介,发布者(publisher) 发布消息到主题,订阅者(subscribe) 从主题订阅消息。

主题使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送。

非持久化的订阅


非持久化的订阅只有当客户端处于激活转态,也就是和MQ保持连接转态才能收到发送到某个主题的消息。

如果消费者处理离线状态,生产者发送的主题消息将会丢失废弃,消费者永远不会收到。

先要订阅注册才能接受到发布,只给订阅者发布消息。

非持久化的订阅下,不能恢复或重新派送一个未签收的消息。

持久的订阅


客户端首先向MQ注册一个自己的身份ID识别码,当这个客户端处理离线时,生产者会为这个ID保存所有发送到主题的消息;

当客户端再次连接到MQ时会根据消费者的ID得到所有当自己处于离线时发送的主题的消息。

持久化的订阅下,才能恢复或重新派送一个未签收的消息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

可乐cc呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值