项目开始

第一步首先需要引入对应的 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. 在Visual C++中使用内联汇编

    一.内联汇编的优缺点 因为在Visual C++中使用内联汇编不需要额外的编译器和联接器,且可以处理Visual C++中不能处理的一些事情,而且可以使用在C/C++中的变量,所以非常方便.内联汇编主 ...

  2. 用 Windows Live Writer 和 SyntaxHighlighter 插件写高亮代码

    博客园内置支持SyntaxHighlighter代码着色,代码着色语法:<pre class='brush:编程语言'>代码</pre>. 需要注意的是:如何你使用Syntax ...

  3. 使用wordpress搭建的网站如何去掉域名中的wordpess

    我们搭建好的网站当以文件夹的形式把wordpress程序放在空间的根目录时,访问的时候要加上文件夹名,访问地址就是:http://www.xxx.com/wordpress,直接用域名是无法访问,解决 ...

  4. web开发调用百度地图API + AK申请

    web开发调用百度地图API + AK申请 要使用百度地图的API我们首先需要在我们的html页面引入js----`` 如何获取百度地图ak: 1.登陆百度地图开发者平台 2.注册百度开发者账号并登陆 ...

  5. Java反射机制调用私有方法

    1.获取目标类: 每个类都有一个class属性,通过实体类的class属性获取: Class clazz = Person.class 通过对象获取.  Person p1 = new Person( ...

  6. JAVA 字符串索引

    String类的substring()方法   截取字符串,在java语言中的用法 1.  public String substring(int beginIndex) 返回一个新字符串,它是此字符 ...

  7. Linxu下JMeter进行接口压力测试

    ****************************************************************************** 本文主要介绍Jmeter脚本如何在Linx ...

  8. 68.最大k乘积问题 (15分)

    C时间限制:3000 毫秒 |  C内存限制:3000 Kb题目内容:设I是一个n位十进制整数.如果将I划分为k段,则可得到k个整数.这k个整数的乘积称为I的一个k乘积.试设计一个算法,对于给定的I和 ...

  9. winform textbox 不能唤醒windows 平板的软键盘解决办法

    这个问题,研究了将近两个小时,baidu,google,好大一会,windows 平板本身的应用程序,必须浏览器,notepad都是可以自动唤起软键盘的,但是我的winfrom 程序就是不可以,起先怀 ...

  10. C语言结构体嵌套

    #include <stdio.h> int main() { /*************************************************** *结构体嵌套:结构 ...