一.JMS编码总体架构
二.队列和主题的区别
1.队列和主题的概念
(1)队列
在点对点的消息传递域中,目的地被称为队列。
(2)主题
在发布订阅消息传递域中,目的地被称为主题。
2.图解
三.消息生产者
1.代码块
(1)pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>demo01</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>demo01 Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- activemq所需要的jar包 -->
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.15.9</version>
</dependency>
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-spring</artifactId>
<version>3.16</version>
</dependency>
<!-- 下面是junit/log4j等基础通用包 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.18</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>demo01</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
(2)生产者类
package com.fengmo.activemq.queue;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
/**
* 消息生产者类
*/
public class JmsProduce {
//定制activemq的地址,注意tcp协议
public static final String ACTIVEMQ_URL = "tcp://192.168.83.129:61616"; //访问activemq的地址
public static final String QUEUE_NAME = "queue01"; //队列名称
public static void main(String[] args) throws JMSException {
//1.创建连接工厂,按照给定的url地址,采用默认用户名和密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2.通过连接工厂,获得连接connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3.创建session,第一个参数事务,第二个参数签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4.创建目的地(具体是队列还是主题)
Queue queue = session.createQueue(QUEUE_NAME);//参数为队列名称
//5.创建消息的生产者
MessageProducer messageProducer = session.createProducer(queue);
//6.通过使用messageProducer生产3条消息发送到MQ的队列里面
for(int i = 0;i < 3;i++){
//7.创建消息
TextMessage textMessage = session.createTextMessage("msg----" + i);//理解一个字符串
//8.通过messageProducer发送到activemq
messageProducer.send(textMessage);
}
//8.关闭资源
messageProducer.close();
session.close();
connection.close();
System.out.println("消息发送完成");
}
}
2.范例
(1)pom.xml
(2)生产者类
3.验证结果【activemq控制台说明】
(1)图解
(2)解析
Number Of Pending Messages | 等待消费的消息 | 这个是当前未出队列的数量。 公式 = 总接受数 - 总出队列数 |
---|---|---|
Number Of Consumers | 消费者数量 | 消费者端的消费者数量 |
Message Enqueued | 进队消息数 | 进入队列的总数量,包括出队列的。这个数量只增不减 |
Messages Dequeued | 出队消息数 | 可以理解为是消费者消费掉的数量 |
(3)总结
- 当有一个消息进入这个队列时,等待消费的消息是1,进入队列的消息是1.
- 当消息消费后,等待消费的消息是0,进入队列的消息是1,出队列的消息是1.
- 再来一条消息时,等待消费的消息是1,进入队列的消息就是2.
四.消息消费者【同步阻塞方式receive】
1.代码块
package com.fengmo.activemq.queue;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
/**
* 消息消费者
*/
public class JmsConsumer {
//定制activemq的地址,注意tcp协议
public static final String ACTIVEMQ_URL = "tcp://192.168.83.129:61616"; //访问activemq的地址
public static final String QUEUE_NAME = "queue01"; //队列名称
public static void main(String[] args) throws JMSException
{
//1.创建连接工厂,按照给定的url地址,采用默认用户名和密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2.通过连接工厂,获得连接connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3.创建session,第一个参数事务,第二个参数签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4.创建目的地(具体是队列还是主题)
Queue queue = session.createQueue(QUEUE_NAME);//参数为队列名称
//5.创建消费者
MessageConsumer messageConsumer = session.createConsumer(queue);
//6.接受消息
while (true)
{
//细节:消息提供者提供的类型,消息消费者就需要什么类型接收,所以强转TextMessage
//receive方法
// 第一种不带参数,表示该对象一直工作不会销毁。
TextMessage textMessage = (TextMessage)messageConsumer.receive();
// 第二种带参数(单位毫秒值),表示该对象3秒内没有接收到任何消息则自动销毁
// TextMessage textMessage = (TextMessage)messageConsumer.receive(3000);
if(null != textMessage)
{
System.out.println("消息消费者接收到的消息是" + textMessage.getText());
}else{
break;
}
}
//7.关闭资源
messageConsumer.close();
session.close();
connection.close();
}
}
2.范例
3.验证结果
(1)图解一【receive方法不带参数】
activemq的控制台
idea的控制台
(2)图解二【receive方法带参数】
activemq的控制台
idea的控制台
五.消息消费者【监听器MessageListener】
1.代码块
package com.fengmo.activemq.queue;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.camel.component.test.TestComponent;
import javax.jms.*;
import java.io.IOException;
/**
* 消息消费者(监听方式)
*/
public class JmsConsumer2 {
//定制activemq的地址,注意tcp协议
public static final String ACTIVEMQ_URL = "tcp://192.168.83.129:61616"; //访问activemq的地址
public static final String QUEUE_NAME = "queue01"; //队列名称
public static void main(String[] args) throws JMSException, IOException {
//1.创建连接工厂,按照给定的url地址,采用默认用户名和密码
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2.通过连接工厂,获得连接connection
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3.创建session,第一个参数事务,第二个参数签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4.创建目的地(具体是队列还是主题)
Queue queue = session.createQueue(QUEUE_NAME);//参数为队列名称
//5.创建消费者
MessageConsumer messageConsumer = session.createConsumer(queue);
//6.通监听的方式来消费消息
messageConsumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if(null != message && message instanceof TextMessage)
{
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("接收的消息是" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
//7.使控制台保存工作
System.in.read(); //细节:如果不加一直保持读取状态,则监听器无法消费消息
//8.关闭资源
messageConsumer.close();
session.close();
connection.close();
}
}
2.范例
3.验证结果
六.消息消费的三种状态
1.先生产,只启动1号消费者。问题:1号消费者能消费消息吗?
答:是。
2.先生产,先启动1号消费者再启动2号消费者。问题:2号消费者还能消费消息吗?
答:只有一号消费者可以消费全部消息。2号没有消费消息。
3.先启动2个消费者,再生产6条消息。请问:消费状况如何?
答:平摊,采取轮询的方式,俩个消费者平均消费3条消息。
六.队列的总结
1.JMS开发的基本步骤
- 创建一个connection factory
- 通过connection factory来创建JMS connection
- 启动JMS connection
- 通过connection创建JMS session
- 创建JMS destination
- 创建JMS producer或者创建JMS message并设置destination
- 创建JMS consumer或者是注册一个JMS message listener
- 发送或者接受JMS message(s)
- 关闭所有的JMS资源
(connection,session,producer,consumer等)
2.消费者的俩种消费
1.同步阻塞方式receive
2.监听器MessageListener【推荐】
3.点对点消息传递域的特点
(1)每个消息只能有一个消费者,类似1对1的关系。好比个人快递自己领取自己。
(2)消息的生产者和消费者之间没有时间上的相关性。无论消费者在生产者发送消息的时候是否处于运行状态,消费者都可以提取消息。好比我们的发送短信,发送者发送后不见得接收者会即收即看。
(3)消息被消费后队列中不会再存储,所以消费者不会消费到已经被消费掉的消息。