官网下载 http://activemq.apache.org/
将安装上传到Linux系统后,无需进行任何操作,直接通过命令启动即可
功能 | 命令 |
---|---|
普通启动 | ./activemq start |
普通停止 | ./activemq stop |
带日志方式启动 | ./activemq start > activemq.log |
功能 | 端口 |
---|---|
后台管理系统图形化界面 | 8161 |
默认进程端口号 | 61616 |
Linux中查看启动状况
功能 | 命令 |
---|---|
查看MQ是否使用 | ps -ef | grep activemq |
查看端口是否使用 | netstat -anp | grep 61616 |
Win中通过浏览器查看,通过IP地址 + 端口号 进入, 账号和密码默认都是admin
登录成功界面
1) IEDA2020.1
2) JDK1.8版本
3) Springboot功能
4) 导入依赖
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-all</artifactId>
<version>5.16.0</version>
</dependency>
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsProduce {
//ActiveMQ地址
public static final String ACTIVEMQ_URL = "tcp://192.168.146.131:61616";
//队列名
public static final String QUEUE_NAME = "queue01";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的生产者
MessageProducer messageProducer = session.createProducer(queue);
//6 生产3条消息发送到消息队列里面
for (int i = 0; i < 3; i++) {
// 7 创建消息
TextMessage textMessage = session.createTextMessage("发送队列测试消息" + i);
// 8 通过消息生产者发布
messageProducer.send(textMessage);
}
//9 关闭资源
messageProducer.close();
session.close();
connection.close();
System.out.println("消息发送到MQ完成");
}
}
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsConsumer {
// 消息接收
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String QUEUE_NAME = "test_queue01";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的消费者
MessageConsumer consumer = session.createConsumer(queue);
//6 循环获取消息
while (true){
TextMessage textMessage = (TextMessage) consumer.receive();
if (textMessage != null){
System.out.println("消费消息----->" + textMessage.getText());
}else {
break;
}
}
//7 关闭资源
consumer.close();
session.close();
connection.close();
System.out.println("消费MQ消息成功");
}
}
功能 | 方法 |
---|---|
接收不到消息一直等待 | receive() |
没有消息则在固定时间后停止 | receive(long var1) |
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;
public class JmsConsumer {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.131:61616";
public static final String QUEUE_NAME = "queue01";
public static void main(String[] args) throws JMSException, IOException {
System.out.println("我是2号消费者");
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的消费者
MessageConsumer consumer = session.createConsumer(queue);
//6 创建消息监听器
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if (message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("消费者接受消息-----" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
// 一定要写 不然没有输出
// 此代码要保证MQ连接成功并且被消费之后,才关闭连接,不然还未执行就已经关闭了
System.in.read();
consumer.close();
session.close();
connection.close();
System.out.println("消息接收到MQ完成");
}
}
序号 | 启动方式 | 结果 |
---|---|---|
1 | 先启动生产者,然后在启动1个消费者 | 消费者全部消费消息 |
2 | 先启动生产者,然后启动1号消费者,成功后在启动2号消费者 | 1号消费者全部消费,2号消费者未消费任何消息 |
3 | 先分别启动1号消费者和2号消费者,然后在启动生产者 | 全部的消息1号消费者和2号消费者每个一半,而不是每个全都消费一遍 |
方式 | 描述 |
---|---|
同步阻塞方式receive() | 订阅者或接收者调用MessageConsumer的receive()方法来接收消息,receive方法在能够接收到消息之前(或超时之前)将一直阻塞 |
异步非阻塞方式(监听器onMessage) | 订阅者或接收者通过MessageConsumer的setMessageListener(MessageListener listener)注册一个消息监听器, |
每个消息只能有1个消费者,类似于1对1的关系,好比个人快递自己领取自己的
消息的生产者和消费者之间没有时间上的相关性,无论消费者在生产者发送消息的时候是否处于运行状态,消费者都可以提取消息,好比我们发送短信,发送者发送以后不见得接收者会即收即看
消息被消费后队列中不会在存储,所有消费者不会消费到已经被消费的消息
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;
public class JmsConsumer {
// 消息接收
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String TOPIC_NAME = "topic-test";
public static void main(String[] args) throws JMSException, IOException {
System.out.println("我是1号消费者");
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地
Topic topic = session.createTopic(TOPIC_NAME);
//5 创建消息的消费者
MessageConsumer consumer = session.createConsumer(topic);
//6 消息
consumer.setMessageListener(new MessageListener() {
@Override
public void onMessage(Message message) {
if (message != null && message instanceof TextMessage){
TextMessage textMessage = (TextMessage) message;
try {
System.out.println("消费者接受消息-----" + textMessage.getText());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
});
System.in.read();
consumer.close();
session.close();
connection.close();
}
}
package com.lin.activemqdemo.demo03_topic;
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsProduce {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String TOPIC_NAME = "topic-test";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
// 两个参数 事务 / 签收
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Topic topic = session.createTopic(TOPIC_NAME);
//5 创建消息的生产者
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
//6 生产3条消息发送到消息队列里面
for (int i = 0; i < 3; i++) {
// 7 创建消息
TextMessage textMessage = session.createTextMessage("topic测试消息" + i);
// 8 通过消息生产者发布
messageProducer.send(textMessage);
}
//9 关闭资源
messageProducer.close();
session.close();
connection.close();
System.out.println("TOPIC消息发送到MQ完成");
}
}
比较项目 | Topic模式对队列 | Queue模式队列 |
---|---|---|
工作模式 | ”订阅-发布“模式,如果当前没有订阅者,消息将会被丢弃,如果有多个订阅者,那么这些订阅者都会收到消息 | “负载均衡”模式,如果当前没有消费者,消息也不会丢弃,如果有多个消费者,那么1条消息只能发送给其中一个消费者,并且要求消费者ack消息 |
有无状态 | 无状态 | Queue数据默认会在mq服务器上以文字形式保存,比如ActiveMQ一般保存在$AMQ_HOME/data/kr-store/data下面,也可以配置成DB存储 |
传递完整性 | 如果没有订阅者,消息会被丢弃 | 消息不回丢弃 |
处理效率 | 由于消息要按照订阅者的数量进行复制,所以处理性能会随着订阅者的增加而明显降低,并且还要结合不同消息协议自身的性能差异 | 由于1条消息只能发送给1个消费者,所以就算消费者再多,性能也就不会有明显降低,当然不同消息协议的具体性能也是有差异的 |
Java Message Service(Java消息服务是JavaEE中的一个技术)
Java消息服务指的是两个应用程序之间进行异步通信的API,它为标准消息协议和消息服务提供了一组通用接口,包括创建、发送、读取消息等,用于支持Java应用程序开发。在JavaEE中,当两个应用程序使用JMS进行通信时,它们之间斌不是之间相连的,而是通过一个共同的消息收发服务组件关联起来以达到解耦/异步削峰的效果
特性 | ActiveMQ | RabbitMQ | Kafka | RockerMQ |
---|---|---|---|---|
PRODUCER-COMSUMER | 支持 | 支持 | 支持 | 支持 |
PUBLISH-SUBSCRIBE | 支持 | 支持 | 支持 | 支持 |
REQUEST-REPLY | 支持 | 支持 | - | 支持 |
API完整性 | 高 | 高 | 高 | 低(静态配置) |
多语言支持 | 支持,Java优先 | 语言无关 | 支持,Java有限 | 支持 |
单机吞吐量 | 万级 | 万级 | 十万级 | 单机万级 |
消息延迟 | - | 微秒级 | 毫秒级 | - |
可用性 | 高(主从) | 高(主从) | 非常高(分布式) | 高 |
消息丢失 | - | 低 | 理论上不会丢失 | - |
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsProducer {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String TOPIC_NAME = "topic-test2";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 创建连接
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地
Topic topic = session.createTopic(TOPIC_NAME);
//5 创建消息的生产者
MessageProducer producer = session.createProducer(topic);
// 消息头设置
// 1)可以统一设置消息为非持久化
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
// 2)可以统一设置消息优先级
producer.setPriority(4);
// 3)可以统一设置过期时间
//producer.setTimeToLive(1000);
for (int i = 0; i < 3; i++) {
//文本消息
TextMessage textMessage = session.createTextMessage("文本消息" + i);
//单独设置某条消息为队列/主题模式
//textMessage.setJMSDestination(topic);
//单独设置某条消息的持久化策略
//textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT);
//单独设置某条消息的过期时间
//textMessage.setJMSExpiration(1000);
//单独设置某条消息的优先级
//textMessage.setJMSPriority(5);
//单独设置某条消息的id
//textMessage.setJMSMessageID("1000");
producer.send(textMessage);
//map类型
MapMessage mapMessage = session.createMapMessage();
mapMessage.setString("hello","world");
//其它类型....
}
// 6 关闭资源
producer.close();
session.close();
connection.close();
System.out.println("消息发送成功");
}
}
// 主要代码有和上面不一样的
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
import java.io.IOException;
public class JmsConsumer_Topic_Persist {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String TOPIC_NAME = "topic-persist";
public static void main(String[] args) throws JMSException, IOException {
System.out.println("我是1号消费者");
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
// 设置订阅者id
connection.setClientID("1号消费者");
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Topic topic = session.createTopic(TOPIC_NAME);
TopicSubscriber topicSubscriber = session.createDurableSubscriber(topic,"remark");
//5 启动
connection.start();;
//6 订阅者接收
Message message = topicSubscriber.receive();
while (message != null){
TextMessage textMessage = (TextMessage) message;
System.out.println("收到的持久化topic:" + textMessage.getText());
//接收消息之后一直监听服务
message = topicSubscriber.receive();
//第一次接收到消息之后,4秒之内没有接收到新消息,服务自动停止
//message = topicSubscriber.receive(4000);
}
session.close();
connection.close();
}
}
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmvProduce_Topic_Persist {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String TOPIC_NAME = "topic-persist";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
//3 创建会话seesion
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Topic topic = session.createTopic(TOPIC_NAME);
//5 创建消息的生产者
MessageProducer messageProducer = session.createProducer(topic);
messageProducer.setDeliveryMode(DeliveryMode.PERSISTENT);
//6 这里在上面设置完持久话在启动
connection.start();
//7 生产3条消息发送到消息队列里面
for (int i = 0; i < 3; i++) {
TextMessage textMessage = session.createTextMessage("topic消息" + i);
messageProducer.send(textMessage);
}
//8 关闭资源
messageProducer.close();
session.close();
connection.close();
System.out.println("TOPIC消息发送到MQ完成");
}
}
序号 | 启动方式 | 结果 |
---|---|---|
1 | 先启动消费者,订阅主题,然后启动生产者 | 消息可以正常接收 |
2 | 先启动1号消费者,然后启动2号消费者,然后启动生产者 | 消息可以正常接收 |
3 | 先启动1号消费者,订阅之后在关闭,然后启动生产者发送消息,再次启动消费者看是否能收到消息? | 1号消费者启动之后之前的消息正常接收 |
需要注意页面订阅者数量变化,可以查看到当前主题的在线人数和离线人数
步骤
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsProduce {
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String QUEUE_NAME = "test_queue01";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
// !!!!!!!!!!!!!!!这是设置事务为 true 开启状态
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的生产者
MessageProducer messageProducer = session.createProducer(queue);
//6 生产3条消息发送到消息队列里面
for (int i = 0; i < 3; i++) {
// 7 创建消息
TextMessage textMessage = session.createTextMessage("发送队列测试消息----" + i);
// 8 通过消息生产者发布
messageProducer.send(textMessage);
}
//9 关闭资源
messageProducer.close();
// 当上面开启事务以后,这里一定要通过commit提交
session.commit();
session.close();
connection.close();
System.out.println("消息发送到MQ完成");
try {
}catch (Exception e){
// 如果代码如果任何异常,可以使用rollback进行回滚
session.rollback();
}
}
}
注意: 当消费者开启事务以后,也必须要commit提交,不然这条消息则没有被消费,下次运行消费者代码会再次获取相同的消息,造成非常常见的问题: 消息重复消费
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsConsumer {
// 消息接收
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String QUEUE_NAME = "test_queue01";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
Session session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的消费者
MessageConsumer consumer = session.createConsumer(queue);
//6 循环获取消息
while (true){
TextMessage textMessage = (TextMessage) consumer.receive(1000);
if (textMessage != null){
System.out.println("消费消息----->" + textMessage.getText());
}else {
break;
}
}
//7 关闭资源
consumer.close();
//这里一定要commit,不然则消息没有被消费,下次运行还会获取相同的消息
//会造成消息重复消费
session.commit();
session.close();
connection.close();
System.out.println("消费MQ消息成功");
}
}
描述 | 代码 | |
---|---|---|
常用 | 自动签收 | Session.AUTO_ACKNOWLEDGE=1 |
常用 | 手动签收 | Session.CLIENT_ACKNOWLEDGE=2 |
允许部分重复签收 | Session.DUPS_OK_ACKNOWLEDGE=3 | |
事务 | Session.SESSION_TRANSACTED=0 |
import org.apache.activemq.ActiveMQConnectionFactory;
import javax.jms.*;
public class JmsConsumer {
// 消息接收
public static final String ACTIVEMQ_URL = "tcp://192.168.146.132:61616";
public static final String QUEUE_NAME = "test_queue01";
public static void main(String[] args) throws JMSException {
//1 创建连接工厂
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(ACTIVEMQ_URL);
//2 通过连接工程,获取连接connection并启动访问
Connection connection = activeMQConnectionFactory.createConnection();
connection.start();
//3 创建会话seesion
// 设置签收为自动签收
Session session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
//4 创建目的地(具体是队列还是主题topic)
Queue queue = session.createQueue(QUEUE_NAME);
//5 创建消息的消费者
MessageConsumer consumer = session.createConsumer(queue);
//6 循环获取消息
while (true){
TextMessage textMessage = (TextMessage) consumer.receive(1000);
if (textMessage != null){
System.out.println("消费消息----->" + textMessage.getText());
// 消息一定要确定签收,不然会造成重复消费
textMessage.acknowledge();
}else {
break;
}
}
//7 关闭资源
consumer.close();
session.close();
connection.close();
System.out.println("消费MQ消息成功");
}
}
测试情况:
事务状态 | 签收状态 | 是否commit() | 是否调用acknowledge() | 结果 | 结论 |
---|---|---|---|---|---|
开启 | 自动签收 | 是 | 否 | 消息不会重复消费 | 事务会帮我们进行手动签收 |
开启 | 自动签收 | 否 | 是 | 消息会重复消费 | 没有commit则签收不管事 |
点对点模式是基于队列的,生产者发消息队列,消费者从队列接收消息,队列的存在使得消息的异步传输成为可能,和我们平常给朋友发送短信类似
1 如果在Session关闭时有部分消息已被接收到但还没有被签收(ack),那当消费者下次连接到相同的队列时,这些消息还会被再次接收
2 队列可以长久地保存消息知道消费者收到消息,消费者不需要因为担心消息会丢失而时刻和队列保持激活的连接状态,充分体现了异步传输模式的优势
JMS Pub/Sub模型定义了如何向一个内容节点发送和订阅消息,这些节点被称作topic
主题可以被认为是消息的传输中介,发布者(publisher)发布消费到主题,订阅者(subscribe)从主题订阅消息
主题使得消息订阅者和消息发布者保持互相独立,不需要接触即可保证消息的传送
客户端首先向MQ注册一个自己的身份ID识别号,当这个客户端处理离线时,生产者会为这个ID保存所有发送到主题的消息,当客户再次连接到MQ时会根据消费者的ID得到所有当自己处理离线时发送到主题的消息
非持久订阅状态下,不能恢复或重新派送一个未签收的消息
持久订阅才能恢复或重新派送一个未签收的消息
相当于一个ActiveMQ服务器示例
说白了,Broker其实就是实现了用代码的形式启动ActiveMQ将MQ嵌入到Java代码中,以便随时用随时启动,在用的时候再去启动,这样能节省了资源,也保证了可靠性
启动命令
./bin/activemq start xbean:file:/usr/local/apache-activemq-5.16.0/conf/activemq02.xml
启动示例
import org.apache.activemq.broker.BrokerService;
public class EmbedBroker {
public static void main(String[] args) throws Exception {
// 在本机启动一个迷你般的ActiveMQ
BrokerService brokerService = new BrokerService();
brokerService.setUseJmx(true);
// 因为要在本机启动,所以地址为本机
brokerService.addConnector("tcp://localhost:61616");
brokerService.start();
}
}
启动之后可以通过JPS查看进程,然后通过消费者和生产者测试
序号 | 名称 | 使用频率 |
---|---|---|
1 | TCP协议 | 默认 |
2 | New I/0协议 | 常用 |
3 | AMQP协议 | |
4 | stomp协议 | |
5 | mqtt协议 | |
6 | ws协议 | |
7 | … |
public static void main(String[] args) throws Exception {
// 在本机启动一个迷你般的ActiveMQ
BrokerService brokerService = new BrokerService();
brokerService.setUseJmx(true);
// 因为要在本机启动,所以地址为本机
brokerService.addConnector(“tcp://localhost:61616”);
brokerService.start();
}
}
启动之后可以通过JPS查看进程,然后通过消费者和生产者测试
## 七、SpringBoot整合ActiveMQ
## 八、ActiveMQ的传输协议
### 1) 面试题
1. 默认的61616端口如何修改
2. 你生产上的链接协议如何配置的? 使用tcp吗?
### 2) 官网
### 3)协议有哪些
| 序号 | 名称 | 使用频率 |
| :--: | :---------: | :------: |
| 1 | TCP协议 | 默认 |
| 2 | New I/0协议 | 常用 |
| 3 | AMQP协议 | |
| 4 | stomp协议 | |
| 5 | mqtt协议 | |
| 6 | ws协议 | |
| 7 | ........... | |
### 4 NIO案例演示