JMS全名Java Message Service,即Java消息服务。我们要学的是ActiveMQ,为什么学着学着就又跑到Java EE中的的JMS呢?可以不学吗?
先看看人家官网怎么说
翻译一下上面的内容
Apache ActiveMQ 速度快,支持许多种跨语言客户端和协议,具有易于使用的企业集成模式和许多高级特性,同时完全支持JMS 1.1。 在来看看ActiveMQ的特征都有哪些,作为Java开发,JMS就成了ActiveMQ技术规范的不二之选。
什么是JMS?
JMS API 由 Sun 和几家合作伙伴公司设计,定义了一组通用接口和相关语义,允许用 Java 编程语言编写的程序与其他消息传递实现进行通信。消息传递是一种软件组件或应用程序之间的通信方法,它允许应用程序创建、发送、接收和读取消息。
消息传递支持松散耦合的分布式通信。组件向目的地发送消息,接收方可以从目的地检索消息。但是,发送方和接收方不必同时可用才能进行通信。事实上,发送者和接收者是处在黑暗森林中,互相不知道对方的存在。发送方和接收方只需要知道要使用的消息格式和目的地即可。在这方面,消息传递不同于紧密耦合的技术,例如远程方法调用 (RMI),后者要求应用程序知道远程应用程序的方法。
JMS API 不仅可以实现松散耦合的通信,还可以:
- 异步:JMS 提供者可以在消息到达时将消息传递给客户端;客户端不必为了接收消息而请求消息。
- 可靠:JMS API 可以确保一条消息只传递一次。
总结一下:JMS是一个利用消息格式和目的地来进行应用程序直接的消息传递方式,并且具有松耦合、异步和可靠的特性。
JMS架构
JMS消息架构有两种非常普遍的模式,分别是点对点,和发布\订阅模式,接下来分别介绍一下
点对点消息传递
点对点模式应用于确保每条消息被一个消费者使用的情况,里面的核心概念是queue,消息发送至queue,消费者消费指定queue的消息。如下图
点对点消息传递的一些特征如下
- 每条消息只有一个消费者
- 消息的发送方和接收方没有时间依赖性。无论客户端发送消息时它是否正在运行,接收方都可以获取消息
- 接收方确认消息并回应
使用场景:当每条消息确保只被一个消费者消成功消费时,就使用点对点模式。
发布/订阅模式
这种模式建立在topic概念下。一图胜千言
发布/订阅消息传递具有以下特征
- 每条消息可以有多个消费者。
- 消费者要订阅指定Topic
- 发布者和订阅者具有时间依赖性。订阅Topic的客户端只能消费在客户端创建订阅后发布的消息,并且订阅者必须继续处于活动状态才能消费消息。
JMS API 也允许订阅者创建持久订阅,当订阅者不活跃时(可能是断开连接等),jms服务器会为订阅者保留消息,等再次活跃就可以获取持久化的消息。
消息消费
JMS的消息本质上是异步的:消息的生产和消费之间没有基本的时间依赖性。但是,JMS 规范在更精确的意义可以通过以下两种方式之一消费:
- 同步: 订阅者或接收者通过调用
接收
方法显式地从目的地获取消息。该接收
方法可以被阻塞,直到消息到达或可能超时。 - 异步:客户端可以向消费者注册消息监听器。每当消息到达目的地时,JMS 提供者通过调用监听器的
onMessage()
方法来传递消息。
JMS编程模型
JMS基本构成组件如下
- JMS管理对象:连接工厂和目的地
- Connections(连接)
- Sessions(会话)
- Message producers
- Message consumers
- Messages
我们主要从这儿学习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。
拿最常用的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();
}
}
效果图
emmmm着实伤害显著,本篇告捷.
越学越越感到自己的弱小,时刻对学术保持敬畏之心,望共勉。欢迎加我VX一起互动学习!
VX号:CXYWG1943132157 最后希望大家能留下一个小赞👍🤷♀️