项目开始

第一步首先需要引入对应的 jar 包

<!-- https://mvnrepository.com/artifact/com.rabbitmq/amqp-client -->
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>

连接 RabbitMQ

连接 RabbitMQ 有两种方式:1.根据特定参数连接 2.根据 URI 连接

根据特定的参数连接(用户名、密码、IP 地址、虚拟 broker、端口号)

// 声明连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 使用连接工厂赋值 userName、password、host、vHost、port 等等
factory.setUsername("userName");
factory.setPassword("password");
factory.setHost("host");
factory.setVirtualHost("vhost");
factory.setPort(5672);
// 创建连接
Connection conn = factory.newConnection();

根据 URI 连接也可以选择使用 URI 的方式来实现

ConnectionFactory factory = new ConnectionFactory();
factory.setUri("amqp://userName:password@host:port/vhost");
Connection connection = factory.newConnection();
System.out.println(connection);
connection.close();

Connection 可以用来创建多个 Channel 实例,但是 Channel 实例不能在线程间共享,应该为每一个线程开辟一个 Channel。线程共享会导致在网络上出现错误的通信帧交错,同时也会影响发送方确认机制的运行,所以多线程间共享 Channel 实例是非线程安全的。

使用队列和交换器

如何声明一个队列和交换器

Channel channel = connection.createChannel();
channel.exchangeDeclare("exchangeName", "direct", true);
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, "exchangeName", "routuingKey");

上面创建了一个持久化的、非自动删除的、绑定类型为 direct 的交换器,同时也创建了一个非持久化的、排他的、自动删除的队列(此队列的名称由 RabbitMQ 自动生成)。

exchangeDeclare 方法详解

exchangeDeclare 有多个重载方法都是由下面的这个方法中参数的缺省构成的。

public DeclareOk exchangeDeclare(String exchange, String type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments) throws IOException;

此方法的返回值是 Exchange.DeclareOk 用来标识成功声明了一个交换器。

参数说明

  1.exchange: 交换器的名称。

  2.type: 交换器的类型。

  3.durable: 设置是否持久化。true 表示持久化 false 表示非持久化。持久化可以将交换器存盘,在服务器重启的时候不会丢失相关信息。

  4.autoDelete: 设置是否自动删除。true 表示自动删除。自动删除的前提是至少有一个队列或者交换器与这个交换器绑定,之后所有与这个交换器绑定的队列或者交换器都与此解绑。注意不能错误地把这个参数理解为: “当与此交换器连接的客户端都断开时,RabbitMQ 会自动删除本交换器”。

  5.internal: 设置是否是内置的。true 则表示内置交换器,客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。

  6.arguments: 其他一些结构化参数。比如 alternate-exchange。

有声明创建交换器的方法,也对应肯定也有删除交换器的方法。其中 exchange 表示交换器的名称,而 ifUnuserd 用来设置在交换器没有被使用的情况下删除,如果设置为 true,则只有再此交换器没有被使用的情况下才会被删除,如果设置为 false,则无论如何这个交换器都要被删除。

public AMQP.Exchange.DeleteOk exchangeDelete(String exchange, boolean ifUnused) throws IOException;
public AMQP.Exchange.DeleteOk exchangeDelete(String exchange, boolean ifUnused) throws IOException;

不带任何参数的 queueDeclare 方法默认创建一个由 RabbitMQ 命名的名称,这种队列也称匿名队列,拥有排他、自动删除、非持久化的属性。

queueDeclare 方法详解

public AMQP.Queue.DeclareOk queueDeclare() throws IOException;
public AMQP.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException;

不带任何参数的 queueDeclare 方法默认创建一个由 RabbitMQ 命名的名称,这种队列也称匿名队列,拥有排他、自动删除、非持久化的属性。

参数说明

  1.queue: 队列的名称。

  2.durable: 设置是否持久化。true 表示持久化 false 表示非持久化。

  3.exclusive: 设置是否排他。true 表示为排他,如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,并在连接断开时自动删除。

    3.1.排他队列是基于连接(Connection)可见的。同一个连接的不同信道(Channel)是可以同时访问同一连接创建的排他队列;

    3.2."首次"是指如果一个连接己经声明了一个排他队列,其他连接是不允许建立同名的排他队列的,这个与普通队列不同:

    3.3.即使该队列是持久化的,一旦连接关闭或者客户端退出,该排他队列都会被自动删除,这种队列适用于一个客户端同时发送和读取消息的应用场景。

  4.autoDelete: 设置是否自动删除。true 表示设置为自动删除。

    4.1.自动删除的前提是:至少有一个消费者连接到这个队列,之后所有与这个队列连接的消费者都断开时,才会自动删除。不能把这个参数错误地理解为:“当连接到此队列的所有客户端断开时,这个队列自动删除”,因为生产者客户端创建这个队列,或者没有消费者客户端与这个队列连接时,都不会自动删除这个队列。

  5.arguments: 设置队列的其他一些参数。如 x-rnessage-ttl 、x-expires 、x -rnax-length 、x-rnax-length-bytes 、x-dead-letter-exchange 、x-dead­letter-routing-key, x-rnax-priority 等。

与交换器对应,关于队列也有删除的相应方法。其中 queue 表示队列名称,而 ifUnuserd 用来设置在队列没有被使用的情况下删除,如果设置为 true,则只有再此队列没有被使用的情况下才会被删除,如果设置为 false,则无论如何这个队列都要被删除。ifEmpty 设置为 true 表示在队列为空(队列里面没有任何消息堆积)的情况下才能够删除。

public AMQP.Queue.DeleteOk queueDelete(String queue) throws IOException;
public AMQP.Queue.DeleteOk queueDelete(String queue, boolean ifUnused, boolean ifEmpty) throws IOException;

还有一个方法用来清空队列中的内容,而不删除队列本身。

public AMQP.Queue.PurgeOk queuePurge(String queue) throws IOException;

exchangeBind 方法详解

除了可以将交换器和队列绑定,还可以将交换器与交换器绑定,绑定方法如出一辙。

public AMQP.Exchange.BindOk exchangeBind(String destination, String source, String routingKey) throws IOException;
public AMQP.Exchange.BindOk exchangeBind(String destination, String source, String routingKey, Map<String, Object> arguments) throws IOException;

参数说明

  1.destination: 需要被绑定的交换器或队列

  2.source: 需要绑定的交换器或队列。

  3.routingKey: 路由键。

  4.其他一些结构化参数。

发送消息

Channel.basicPublish 方法是发送消息。

String message = "Hello Word!";
channel.basicPublish("exchangeName", "routingKey", null, message.getBytes());

方法概览

public void basicPublish(String exchange, String routingKey, AMQP.BasicProperties props, byte[] body) throws IOException;
public void basicPublish(String exchange, String routingKey, boolean mandatory, AMQP.BasicProperties props, byte[] body) throws IOException;
public void basicPublish(String exchange, String routingKey, boolean mandatory, boolean immediate, AMQP.BasicProperties props, byte[] body) throws IOException;

参数说明

  1.exchange: 交换器的名称,指明消息需要发送到哪个交换器中。如果设置为空串。则消息会被发送到 RabbitMQ 默认的交换器中。

  2.routhingKey: 路由键,交换器根据路由键将消息存储到相应的队列之中。

  3.props: 消息的基本属性集。其包含 14 个属性成员,分别有 contentType、content Encoding、headers(Map<String, Object>)、deliveryMode、priority、correlationld、replyTo、expiration、messageld、timestamp、type、userld、appld、clusterld。

  4.body: 消息体需要发送的消息。

  5.mandatory: true 表示如果交换器根据路由键无法找到符合条件的队列时会将消息返回给生产者 false 时将消息直接丢弃。

  6.immediate: true 表示交换器将消息路由到队列发现并不存在消费者时那么此消息不会被放入队列。

消费消息

RabbitMQ 消息模式分两种: 推 Push 模式和拉 Pull 模式。推模式采用 Basic.Consume 进行消费,而拉则是调用 Basic.Get 进行消费。我们只介绍推模式,对拉模式感兴趣可自行研究。

Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
channel.basicQos(1);
DeliverCallback deliverCallback = new DeliverCallback() {
@Override public void handle(String s, Delivery delivery) throws IOException {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println("RabbitMqWorkRec1Test Received: " + message);
channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);
}
};
channel.basicConsume(QUEUE_NAME, false, deliverCallback, new CancelCallback() {
@Override public void handle(String s) throws IOException {
System.out.println("RabbitMqWorkRec1Test CancelCallback==========> " + s);
}
});

以上代码中显式的 ack 操作对于消费者来说是非常必要的,可以防止必须要的消息丢失。

方法概览

public String basicConsume(String queue, boolean autoAck, DeliverCallback deliverCallback, CancelCallback cancelCallback) throws IOException;
public String basicConsume(String queue, boolean autoAck, String consumerTag, boolean noLocal, boolean exclusive, Map<String, Object> arguments, Consumer callback) throws IOException;

参数说明

  1.queue: 队列名称。

  2.autoAck: 设置是否自动确认。true 表示不自动确认,建议设置为 false。

  3.consumerTag: 消费者标签,用来区分多个消费者。

  4.noLocal: 设置为 true 表示不能将一个连接中生产者发送的消息传给这个连接的消费者。

  5.exclusive: 设置是否排他。

  6.arguments: 设置消费者的其他参数。

  7.callback: 设置消费者的回调函数。用来处理 RabbitMQ 推送过来的消息。

Demo 示例

最后看来下完整的生产消费者示例。

生产者

public class RabbitMqPubTest {
private static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) {
Connection conn = null;
Channel channel = null;
try {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("userName");
factory.setPassword("password");
factory.setHost("host");
factory.setVirtualHost("vhost");
factory.setPort(5672);
conn = factory.newConnection();
channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
String message = "Hello Word!";
channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
System.out.println("RabbitMqPubTest send: " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != channel) {
try {
channel.close();
} catch (Exception e) {
e.printStackTrace();
}
}
if (null != conn) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}

消费者

public class RabbitMqSub01Test {
private static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("userName");
factory.setPassword("password");
factory.setHost("host");
factory.setVirtualHost("vhost");
factory.setPort(5672);
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
String queueName = channel.queueDeclare().getQueue();
System.out.println("RabbitMqSub01Test queueName: " + queueName);
channel.queueBind(queueName, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = new DeliverCallback() {
@Override public void handle(String s, Delivery delivery) throws IOException {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println("RabbitMqSub01Test Received: " + message);
}
};
channel.basicConsume(queueName, true, deliverCallback, new CancelCallback() {
@Override public void handle(String s) throws IOException { }
});
}
} public class RabbitMqSub02Test {
private static final String EXCHANGE_NAME = "test_exchange_fanout"; public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername("userName");
factory.setPassword("password");
factory.setHost("host");
factory.setVirtualHost("vhost");
factory.setPort(5672);
Connection conn = factory.newConnection();
Channel channel = conn.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
String queueName = channel.queueDeclare().getQueue();
System.out.println("RabbitMqSub02Test queueName: " + queueName);
channel.queueBind(queueName, EXCHANGE_NAME, "");
DeliverCallback deliverCallback = new DeliverCallback() {
@Override public void handle(String s, Delivery delivery) throws IOException {
String message = new String(delivery.getBody(), StandardCharsets.UTF_8);
System.out.println("RabbitMqSub02Test Received: " + message);
}
};
channel.basicConsume(queueName, true, deliverCallback, new CancelCallback() {
@Override public void handle(String s) throws IOException { }
});
}
}

以上是 java 常用 rabbitMQ API 操作,感谢观看!不足之处请评论!

Rabbit MQ 客户端 API 开发的更多相关文章

  1. Rabbit MQ 客户端 API 进阶

    之前说了一些基础的概念及使用方法,比如创建交换器.队列和绑定关系等.现在我们再来补充一下细节性的东西. 备份交换器 通过声明交换器的时候添加 alternate-exchange 参数来实现. Con ...

  2. Rabbit MQ 学习参考

    网上的教程虽然多,但是提供demo的比较少,或者没有详细的说明,因此,本人就照着网上的教程做了几个demo,并把代码托管在码云,供有需要的参考. 项目地址:https://gitee.com/dhcl ...

  3. celery rabbit mq 详解

    Celery介绍和基本使用 Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, ...

  4. Spring Boot:使用Rabbit MQ消息队列

    综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程则可以 ...

  5. Spring boot集成Rabbit MQ使用初体验

    Spring boot集成Rabbit MQ使用初体验 1.rabbit mq基本特性 首先介绍一下rabbitMQ的几个特性 Asynchronous Messaging Supports mult ...

  6. 使用Rabbit MQ消息队列

    使用Rabbit MQ消息队列 综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息 ...

  7. 在 Windows 上安装Rabbit MQ 指南

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Public License开源协议.采用 Erlang 实现的工业级的消息队列(MQ)服务器. Ra ...

  8. (转)在 Windows 上安装Rabbit MQ 指南

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Public License开源协议.采用 Erlang 实现的工业级的消息队列(MQ)服务器. Ra ...

  9. Rabbit MQ 消息确认和持久化机制

    一:确认种类 RabbitMQ的消息确认有两种.一种是消息发送确认,用来确认生产者将消息发送给交换器,交换器传递给队列的过程中消息是否成功投递.发送确认分为两步,一是确认是否到达交换器,二是确认是否到 ...

随机推荐

  1. Python 爬取各大代理IP网站(元类封装)

    import requests from pyquery import PyQuery as pq base_headers = { 'User-Agent': 'Mozilla/5.0 (Windo ...

  2. selenium之 文件上传所有方法整理总结

    本文转载“灰蓝”的原创博客.http://blog.csdn.net/huilan_same/article/details/52439546 文件上传是所有UI自动化测试都要面对的一个头疼问题,今天 ...

  3. Amazon Linux AMI 2015.09 (HVM)平台搭建lamp

    更新yum yum update 安装Apache: yum install -y httpd 安装完之后,重新启动 service httpd restart 将Apache设置为开机启动 chkc ...

  4. 自旋锁spinlock

    1 在单处理器上的实现 单核系统上,不存在严格的并发,因此对资源的共享主要是多个任务分时运行造成的. 只要在某一时段,停止任务切换,并且关中断(对于用户态应用程序,不大可能与中断处理程序抢临界区资源) ...

  5. jquery插件小集合

    一.滑动轮播插件Swiper Swiper官网http://www.swiper.com.cn/, 这款插件移动端,pc端均试用 二.jquery-tmpl----让你从拼接字符串中解放出来 官方下载 ...

  6. vue中wath的源码实现

    前言 阅读本节,需要理解vue的数据驱动原理. 看这样一段代码 new Vue({ data: { msg: 'hello', say: 'hello world', }, watch: { msg( ...

  7. python_django_The requested URL /sunck/login/sunck/showmain/ was not found on this server.错误

    在我url匹配过程中出现了这样一个错误: 网页显示: Not Found The requested URL /sunck/login/sunck/showmain/ was not found on ...

  8. Dao层结合Service层处理异常

    1. 接口存在异常不利于解耦. 2. 将编译时异常转化为运行时异常或其子类,通知上层,上层可以根据自身能力选择处理或向上抛出. 举例: 将UserDao中的SQLException转化为DaoExce ...

  9. Java集合中的Map接口怎么使用?

    Map(双列集合框架) 1.Map接口及实现类概述 Map 接口提供三种collection 视图,允许以键集.值集或键-值映射关系集的形式查看某个映射的内容.映射顺序 定义为迭代器在映射的 coll ...

  10. Python 分布式锁

    1,数据一致性 当多个进程/线程对同一个共享资源读写,会因为资源的争夺而出现混乱,导致数据不一致. 如下图: 在数据库的原始数据是 d0,上图的处理流程如下: t1 时刻,有两个数据源的数据 d1,d ...