阅读 344

ActiveMQ必知必会-JMS

JMS全名Java Message Service,即Java消息服务。我们要学的是ActiveMQ,为什么学着学着就又跑到Java EE中的的JMS呢?可以不学吗?

先看看人家官网怎么说 image-20210616163717320.png

翻译一下上面的内容

Apache ActiveMQ 速度快,支持许多种跨语言客户端和协议,具有易于使用的企业集成模式和许多高级特性,同时完全支持JMS 1.1。 在来看看ActiveMQ的特征都有哪些,作为Java开发,JMS就成了ActiveMQ技术规范的不二之选。

image-20210616164219752.png

什么是JMS?

JMS API 由 Sun 和几家合作伙伴公司设计,定义了一组通用接口和相关语义,允许用 Java 编程语言编写的程序与其他消息传递实现进行通信。消息传递是一种软件组件或应用程序之间的通信方法,它允许应用程序创建、发送、接收和读取消息。

消息传递支持松散耦合的分布式通信。组件向目的地发送消息,接收方可以从目的地检索消息。但是,发送方和接收方不必同时可用才能进行通信。事实上,发送者和接收者是处在黑暗森林中,互相不知道对方的存在。发送方和接收方只需要知道要使用的消息格式和目的地即可。在这方面,消息传递不同于紧密耦合的技术,例如远程方法调用 (RMI),后者要求应用程序知道远程应用程序的方法。

JMS API 不仅可以实现松散耦合的通信,还可以:

  • 异步:JMS 提供者可以在消息到达时将消息传递给客户端;客户端不必为了接收消息而请求消息。
  • 可靠:JMS API 可以确保一条消息只传递一次。

总结一下:JMS是一个利用消息格式和目的地来进行应用程序直接的消息传递方式,并且具有松耦合、异步和可靠的特性。

JMS架构

JMS消息架构有两种非常普遍的模式,分别是点对点,和发布\订阅模式,接下来分别介绍一下

点对点消息传递

点对点模式应用于确保每条消息被一个消费者使用的情况,里面的核心概念是queue,消息发送至queue,消费者消费指定queue的消息。如下图

点对点消息传递示意图,显示客户端 1 向队列发送消息,客户端 2 使用并确认消息

点对点消息传递的一些特征如下

  • 每条消息只有一个消费者
  • 消息的发送方和接收方没有时间依赖性。无论客户端发送消息时它是否正在运行,接收方都可以获取消息
  • 接收方确认消息并回应

使用场景:当每条消息确保只被一个消费者消成功消费时,就使用点对点模式。

发布/订阅模式

这种模式建立在topic概念下。一图胜千言

发布/订阅消息图,显示客户端 1 向主题发布消息,以及将消息传递给该主题的两个订阅者

发布/订阅消息传递具有以下特征

  • 每条消息可以有多个消费者。
  • 消费者要订阅指定Topic
  • 发布者和订阅者具有时间依赖性。订阅Topic的客户端只能消费在客户端创建订阅后发布的消息,并且订阅者必须继续处于活动状态才能消费消息。

JMS API 也允许订阅者创建持久订阅,当订阅者不活跃时(可能是断开连接等),jms服务器会为订阅者保留消息,等再次活跃就可以获取持久化的消息。

消息消费

JMS的消息本质上是异步的:消息的生产和消费之间没有基本的时间依赖性。但是,JMS 规范在更精确的意义可以通过以下两种方式之一消费:

  • 同步: 订阅者或接收者通过调用接收方法显式地从目的地获取消息。该接收方法可以被阻塞,直到消息到达或可能超时。
  • 异步:客户端可以向消费者注册消息监听器。每当消息到达目的地时,JMS 提供者通过调用监听器的onMessage()方法来传递消息。

JMS编程模型

JMS基本构成组件如下

  • JMS管理对象:连接工厂和目的地
  • Connections(连接)
  • Sessions(会话)
  • Message producers
  • Message consumers
  • Messages

JMS API 编程模型图:连接工厂、连接、会话、消息生产者、消息消费者、消息和目的地

我们主要从这儿学习ActiveMQ,要能管中窥豹,举一反三,细节不必太深入了解,我总说学一门技术要高屋建瓴,了解其概括,在来一点点根据实际深入。所以上面看懂英文然后结合图片知道消息的传递流程就行,就不各个组件一一介绍了。

稍微得提一下消费者,上面不是提了消息消费的两种模式,这里列举一下实例,便于理解。

阻塞模式接受消息

connection.start();
Message m = consumer.receive();
connection.start();
Message m = consumer.receive(1000); // time out after a second
复制代码

异步监听接收消息

Listener myListener = new Listener();
consumer.setMessageListener(myListener);
connection.start();
复制代码

Listener中的onMessage()方法则是需要实现消费逻辑的地方

JMS消息结构

JMS 消息主要由三部分组成:消息头、消息属性、消息体

消息头主要包含了一些描述消息的信息,包括时间戳、目的地、消息ID等;消息属性则是可以自定义一些属性给消息,也可以附上selector;消息体则是我们直接利用的对象,JMS提供了5种格式供我们选择,TextMessage、MapMessage、BytesMessage、StreamMessage、ObjectMessage最后还有一种无消息内容的标识消息体Message。

image-20210617145444259.png 拿最常用的TextMessage举例,看看如何发送消息。

TextMessage message = session.createTextMessage();
message.setText(msg_text);     // msg_text is a String
producer.send(message);
复制代码

消息消费也需要利用同样消息体进行消费

Message m = consumer.receive();
if (m instanceof TextMessage) {
    TextMessage message = (TextMessage) m;
    System.out.println("Reading message: " + message.getText());
} else {
    // Handle error
}
复制代码

实战案例

消息生产者

package com.work.mq;


import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * 类作用: 消息生产者
 * 作者: 八月的冰阔落
 * @description  activeMQ版本 5.10.0;
 *       端口说明8161是前端控制页面端口,61616是服务器运行端口
 * 创建时间:  2021-05-12 11:13
 */
public class JmsProduce {
    private static final String ACTIVEMQ_URL = "tcp://localhost:61616";
    private static final String QUEUE_NAME = "welcome_into_activemq_world";
    public static void main(String[] args) throws JMSException {
        //1.创建连接工厂、按照给定得url地址、采用默认用户名和编码
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2.通过连接工厂、获得连接connection并启动访问
        Connection connection = connectionFactory.createConnection();
        connection.start();
        //3.创建会话session,    第一个叫事务/第二个叫签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列Queue还是主题Topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5.创建消息生产者
        MessageProducer messageProducer = session.createProducer(queue);
        messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
        //6.通过使用消息生产者producer发送消息
        for (int i = 0; i < 3; i++) {
            TextMessage message = session.createTextMessage("msg----瑶瑶攻击---hp-" + i);
            messageProducer.send(message);
        }
        //7.关闭资源
        messageProducer.close();
        session.close();
        connection.close();
    }
}
复制代码

启动消费者

package com.work.mq;

import org.apache.activemq.ActiveMQConnectionFactory;

import javax.jms.*;

/**
 * 类作用:消息消费者
 * 作者: 八月的冰阔乐
 * 创建时间:  2021-05-12 12:33
 */
public class JmsConsumer {
    private static final String ACTIVEMQ_URL = "tcp://localhost:61616";
    private static final String QUEUE_NAME = "welcome_into_activemq_world";
    public static void main(String[] args) throws Exception{
        ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
        //2.通过连接工厂、获得连接connection并启动访问
        Connection connection = connectionFactory.createConnection();
        connection.start();
        //3.创建会话session,    第一个叫事务/第二个叫签收
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        //4 创建目的地(具体是队列Queue还是主题Topic)
        Queue queue = session.createQueue(QUEUE_NAME);
        //5.创建消费者
        MessageConsumer consumer = session.createConsumer(queue);
        while (true){
            TextMessage message = (TextMessage) consumer.receive();
            if (message != null){
                System.out.println("*****消费者接收到消息:"+message.getText());
            }else {
                break;
            }
        }
        //7.关闭资源
        consumer.close();
        session.close();
        connection.close();

    }
}
复制代码

效果图

image-20210616071150355.png

emmmm着实伤害显著,本篇告捷.

越学越越感到自己的弱小,时刻对学术保持敬畏之心,望共勉。欢迎加我VX一起互动学习!

VX号:CXYWG1943132157

最后希望大家能留下一个小赞👍🤷‍♀️

文章分类
后端