分布式消息中间件:RabbitMq
RabbitMq是最广泛被使用的消息代理,类似于ActiveMq,它是一个分布式的消息中间件。
上图来自于官网:是说RabbitMq迄今已经在全球小型企业和大型企业有超过35000个生产部署。也就是说有35000个产品使用了RabbitMq。它是当今最流行的开源消息代理。它也是一个轻量级的并且可以很容易的部署在本地和云环境。它支持多个消息协议。它也可以部署在分布式和联合配置中,以满足高规模,高可用的需要。它能在许多不同的操作系统和云环境中运行,并且为许多主流语言提供了广泛的开发者工具。
RabbitMq的安装和使用:
安装:在下载页面找到对应的操作系统进行安装,这里是Ubuntu
上图来自于官网:是说rabbitmq服务器包含在标准的Debian和Ubuntu仓库中,然而,包含的版本通常在RabbitMq发布几个月之后。
要安装RabbitMq的最近的版本有两种方式:
第一种方式:使用在bintray或者包云上的apt仓库安装,这种方式是高度推荐的。
bintray是什么?要说到bintray首先要说Jcenter,Jcenter是一个代码库,是一个公共的存储控件,而bintray是Jcenter的提供商。
第二种方式:下载这个包,使用dpkg -i安装,这种方式需要手动安装所有依赖项。
上图来自于官网:意思是说,这个接下来的指南主要是针对在Debian以及Debian的衍生物像Ubuntu下安装RabbitMq,它包含这些方面:
从bintray或者包云上的apt仓库安装。最近的Erlang/Otp版本的安装在apt仓库的第三部分。
这里使用第一种方式安转:
安装地址:
http://www.rabbitmq.com/install-debian.html
先安装ErLang在安装RabbitMq
启动,停止,重启Rabbitmq:
当安装RabBMQ服务器包时,默认情况下,服务器作为守护进程启动。它将作为非特权用户RabByMQ运行。
eg:service rabbitmq-server start
配置RabbitMq:
在大多数系统中,节点应该能够以所有默认值启动和运行。请参阅配置指南,了解更多的开发指南和生产清单。
注意:服务器安装运行作为系统用户RabByMQ。如果更改节点数据库或日志的位置,则必须确保该文件属于该用户(并且还更新环境变量)。
端口访问:
SELinux和类似的机型可能会阻止RabbitMq绑定端口,当出现这种情况的时候,RabbitMq会启动失败。防火墙也会阻止节点和CLI工具相互通信。因此,要确保以下端口被打开:
4369端口:epmd,RabbitMq节点和CLI工具使用的对等点发现服务。
什么是 epmd ?
在《Erlang/OTP 并发编程实战》中,对 epmd 有如下描述:
epmd 代表 Erlang 端口映射守护进程(Erlang Port Mapper Daemon)。
每启动一个节点,都会检查本地机器上是否运行着 epmd ,如果没有,节点就会自行启动 epmd 。
epmd 会追踪在本地机器上运行的每个节点,并记录分配给它们的端口。
当一台机器上的 Erlang 节点试图与某远程节点通信时,本地的 epmd 就会联络远程机器上的 epmd(默认使用 TCP/IP 端口 4369),询问在远程机器上有没有叫相应名字的节点。如果有,远程的 epmd 就会回复一个端口号,通过该端口便可直接与远程节点通信。
epmd 不会自动搜索其他 epmd ,只有在某个节点主动搜寻其他节点时通信才能建立。
5672,5671端口:AMQP协议使用的端口
25672端口:用于节点间和CLI工具通信(Erlang分发服务器端口),并从动态范围分配(默认为单个端口,计算为AMQP端口+ 20000)。除非这些端口上的外部连接真的是必需的(例如,集群使用联盟或CLI工具在子网之外的机器上),这些端口不应该公开暴露。详情请参阅网络指南。
35672-35682端口:CLI工具(Erlang分发客户端端口)用于与节点通信,并从动态范围分配(计算为服务器分发端口+ 10000通过服务器分发端口+ 10010)。详情请参阅网络指南。
15672端口:HTTP API客户端、管理UI和RabByMQADmin(只有启用管理插件)
61613,61614端口:STOMP客户端不带TLS,只有启用STOMP插件。
什么是TLS?TLS是安全传输层协议,包括TLS记录协议和TLS握手协议。
1883,8883端口:MQTT客户端不带TLS,只有启用MQTT插件。
15674端口:STOMP的Websocket客户端使用的端口,只有Web STOMP插件启用才可以使用。
15675端口:MQTT的Websocket客户端使用的端口,只有Web MQTT插件启用才可以使用。
管理页面地址:localhost:15672 帐号guest 密码guest
RabbitMQ管理页面:RabbitMQ-Management插件提供基于Http Api的方式,监控和管理RabbitMq服务器。
RabbitMq的java使用:
连接和通道以及断开连接:
第一步:新建maven或者Gradle项目,引入依赖(推荐Maven和Gradle)
这里新建一个名为rabbitMq_connection的Gradle项目,并且引入依赖:
ConnectRabbitMq.java代码如下:(第一种方式)
package com.refrain.rabbitmq;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
运行信息如下:
所连接的rabbitMq客户端的相关信息:
product----RabbitMQ
所连接的rabbitMq客户端的相关信息:
copyright----Copyright (c) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq客户端的相关信息:
capabilities----{exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, basic.nack=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq客户端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq客户端的相关信息:
version----5.3.0
所连接的rabbitMq客户端的相关信息:
platform----Java
所连接的rabbitMq服务器端的相关信息:
cluster_name----rabbit@localhost
所连接的rabbitMq服务器端的相关信息:
copyright----Copyright (C) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq服务器端的相关信息:
product----RabbitMQ
所连接的rabbitMq服务器端的相关信息:
capabilities----{consumer_priorities=true, exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, per_consumer_qos=true, basic.nack=true, direct_reply_to=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq服务器端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq服务器端的相关信息:
version----3.7.7
所连接的rabbitMq服务器端的相关信息:
platform----Erlang/OTP 21.0.3
打开管理页面:当前会有一个连接:
ConnectRabbitMq_UseUri.java(第二种方式,使用Uri的方式连接RabbitMq)
package com.refrain.rabbitmq;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UseUri {
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
// 第二步:创建连接
Connection connection = null;
try {
connectionFactory.setUri("amqp://guest:[email protected]:5672");
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UseUri {
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
// 第二步:创建连接
Connection connection = null;
try {
connectionFactory.setUri("amqp://guest:[email protected]:5672");
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
}
运行信息:
所连接的rabbitMq客户端的相关信息:
product----RabbitMQ
所连接的rabbitMq客户端的相关信息:
copyright----Copyright (c) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq客户端的相关信息:
capabilities----{exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, basic.nack=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq客户端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq客户端的相关信息:
version----5.3.0
所连接的rabbitMq客户端的相关信息:
platform----Java
所连接的rabbitMq服务器端的相关信息:
cluster_name----rabbit@localhost
所连接的rabbitMq服务器端的相关信息:
copyright----Copyright (C) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq服务器端的相关信息:
product----RabbitMQ
所连接的rabbitMq服务器端的相关信息:
capabilities----{consumer_priorities=true, exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, per_consumer_qos=true, basic.nack=true, direct_reply_to=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq服务器端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq服务器端的相关信息:
version----3.7.7
所连接的rabbitMq服务器端的相关信息:
platform----Erlang/OTP 21.0.3
管理页面:
ConnectRabbitMq_Channel.java代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_Channel {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
public static void main(String[] args) throws IOException, TimeoutException {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
Channel channel = null;
try {
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
// Channel作用是用于发送消息和接收消息的通道(不论发送成功还是失败服务器端都可以监控客户端连接事件)
System.out.println("***********************************************************************************************");
channel = connection.createChannel();
System.out.println("通道信息:" + channel.getConnection() + "通道数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
finally {
// 关闭通道
if(channel != null) {
channel.close();
}
// 关闭连接
if(connection != null) {
connection.close();
}
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_Channel {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
public static void main(String[] args) throws IOException, TimeoutException {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
Channel channel = null;
try {
connection = connectionFactory.newConnection();
connection.getClientProperties().entrySet().parallelStream().forEachOrdered(clientInfo -> {
System.out.println("所连接的rabbitMq客户端的相关信息:");
System.out.println(clientInfo.getKey() + "----" + clientInfo.getValue());
});
connection.getServerProperties().entrySet().parallelStream().forEachOrdered(serverInfo -> {
System.out.println("所连接的rabbitMq服务器端的相关信息:");
System.out.println(serverInfo.getKey() + "----" + serverInfo.getValue());
});
// Channel作用是用于发送消息和接收消息的通道(不论发送成功还是失败服务器端都可以监控客户端连接事件)
System.out.println("***********************************************************************************************");
channel = connection.createChannel();
System.out.println("通道信息:" + channel.getConnection() + "通道数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
finally {
// 关闭通道
if(channel != null) {
channel.close();
}
// 关闭连接
if(connection != null) {
connection.close();
}
}
}
}
运行信息:
所连接的rabbitMq客户端的相关信息:
product----RabbitMQ
所连接的rabbitMq客户端的相关信息:
copyright----Copyright (c) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq客户端的相关信息:
capabilities----{exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, basic.nack=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq客户端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq客户端的相关信息:
version----5.3.0
所连接的rabbitMq客户端的相关信息:
platform----Java
所连接的rabbitMq服务器端的相关信息:
cluster_name----rabbit@localhost
所连接的rabbitMq服务器端的相关信息:
copyright----Copyright (C) 2007-2018 Pivotal Software, Inc.
所连接的rabbitMq服务器端的相关信息:
product----RabbitMQ
所连接的rabbitMq服务器端的相关信息:
capabilities----{consumer_priorities=true, exchange_exchange_bindings=true, connection.blocked=true, authentication_failure_close=true, per_consumer_qos=true, basic.nack=true, direct_reply_to=true, publisher_confirms=true, consumer_cancel_notify=true}
所连接的rabbitMq服务器端的相关信息:
information----Licensed under the MPL. See http://www.rabbitmq.com/
所连接的rabbitMq服务器端的相关信息:
version----3.7.7
所连接的rabbitMq服务器端的相关信息:
platform----Erlang/OTP 21.0.3
***********************************************************************************************
通道信息:amqp://[email protected]:5672/通道数量:1
管理页面:可以看到这里创建了一个消息通道。
连接就意味着长期活跃,底层协议是为了长时间运行的连接而设计和优化的。这就意味着为每个操作打开新连接(例如:发布的消息)是不必要的,并且官方反对这么做,因为它会引起很大的网络往返和开销。
通道也意味着长期活跃,但是由于许多可以恢复的协议错误会导致通道关闭。通道的生命周期可能比它的连接时间短。为每个操作打开和关闭一个新通道是没必要的。但是可以根据情况适当的建立多个通道。当有需要的时候,考虑使用通道。
通道级别异常,例如试图消费一个不存在的消息队列将导致通道关闭。一个关闭了的通道将不再被使用,并且将不再接收来自于服务器的事件(例如,消息传递的事件)。通道级别异常将被rabbitmq记录,并且,将为这个通道初始化一个关闭序列。
客户端使用交换和队列,这是协议的高级构建块。在使用它之前必须进行声明,声明任何类型的对象只需要确保存在该名称,必要的时候创建一个名称。
继续之前的例子,下面的代码声明了一个交易和一个命名的队列,然后将它们绑定在一起。
代码如下:
ConnectRabbitMq_UsingExchangeAndQueue.java(如果只有一个客户端使用它,那么队列名称就可以使用默认生成的名称(每次启动客户端都会随机生成),如果没有客户端使用,这个队列将被自动清除)
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
String queueName = channel.queueDeclare().getQueue();
/**
* Bind a queue to an exchange, with no extra arguments.
* @see com.rabbitmq.client.AMQP.Queue.Bind
* @see com.rabbitmq.client.AMQP.Queue.BindOk
* @param queue the name of the queue
* @param exchange the name of the exchange
* @param routingKey the routing key to use for the binding
* @return a binding-confirm method if the binding was successfully created
* @throws java.io.IOException if an error is encountered
*/
channel.queueBind(queueName, EXCHANGETEST, ROUTING);
System.out.println("连接数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
String queueName = channel.queueDeclare().getQueue();
/**
* Bind a queue to an exchange, with no extra arguments.
* @see com.rabbitmq.client.AMQP.Queue.Bind
* @see com.rabbitmq.client.AMQP.Queue.BindOk
* @param queue the name of the queue
* @param exchange the name of the exchange
* @param routingKey the routing key to use for the binding
* @return a binding-confirm method if the binding was successfully created
* @throws java.io.IOException if an error is encountered
*/
channel.queueBind(queueName, EXCHANGETEST, ROUTING);
System.out.println("连接数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
运行信息:
管理页面:
可以看到上面有一条我们创建的名为EXCHANGETEST的交换信息。点击这个交换信息:
同理,我们可以看到连接信息和通道信息:
连接信息:
然后,我们看看官方文档:
channel.exchangeDeclare(exchangeName, "direct", true);
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, exchangeName, routingKey);
这种方式的绑定将声明下列对象,这些对象都使用附加参数进行自定义,并且没有特殊的依据。
这两个对象分别是:
1.一个持久的,非自动删除的直接类型的交换
2.一个具有生成名称的非持久的,独占的,自动删除的队列。
上面的函数调用是通过一个给定的路由密钥将队列和交换绑定在一起。
请注意:这是一个典型的声明队列的方式,当只有一个客户端想要使用它的时候,他不需要一个众所周知的名称(队列名称)。没有客户端使用它的时候,这个队列将被自动删除。
如果有几个客户端,想要共享这个一个有名的队列(可以指定它是否持久,是否独占,是否自动删除)。下面的代码是合适的:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_wellknownname {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列(使用特定的名称的时候可以指定这个队列是否持久,是否独占,是否自动删除)
channel.queueDeclare(QUEUETEST, true, false, false, null);
/**
* Bind a queue to an exchange, with no extra arguments.
* @see com.rabbitmq.client.AMQP.Queue.Bind
* @see com.rabbitmq.client.AMQP.Queue.BindOk
* @param queue the name of the queue
* @param exchange the name of the exchange
* @param routingKey the routing key to use for the binding
* @return a binding-confirm method if the binding was successfully created
* @throws IOException if an error is encountered
*/
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
System.out.println("连接数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_wellknownname {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列(使用特定的名称的时候可以指定这个队列是否持久,是否独占,是否自动删除)
channel.queueDeclare(QUEUETEST, true, false, false, null);
/**
* Bind a queue to an exchange, with no extra arguments.
* @see com.rabbitmq.client.AMQP.Queue.Bind
* @see com.rabbitmq.client.AMQP.Queue.BindOk
* @param queue the name of the queue
* @param exchange the name of the exchange
* @param routingKey the routing key to use for the binding
* @return a binding-confirm method if the binding was successfully created
* @throws IOException if an error is encountered
*/
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
System.out.println("连接数量:" + channel.getChannelNumber());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
当客户端关闭的时候,如果队列是持久的,仍然可以在管理页面看到:
队列和交换可以被动地声明,一个被动的声明会简单的检查提供名称的实体是否存在,如果存在,这个操作就是no-op对于队列成功的被动声明将返回和主动声明一样的信息,即队列中就绪状态的消费者和消息的数量。如果实体不存在,这个操作将以通道级别异常宣告失败。此后,这个通道将不再被使用。应该打开一个新的通道。通常来说,使用一次性的(临时的)通道进行被动声明。
代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_passive_declare {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 被动声明
AMQP.Queue.DeclareOk response = channel.queueDeclarePassive(QUEUETEST);
System.out.println("消费者数量:" + response.getConsumerCount());
System.out.println("消息数量:" + response.getMessageCount());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_passive_declare {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 被动声明
AMQP.Queue.DeclareOk response = channel.queueDeclarePassive(QUEUETEST);
System.out.println("消费者数量:" + response.getConsumerCount());
System.out.println("消息数量:" + response.getMessageCount());
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
一些常见的操作有一个非等待版本,就是不等待服务器响应,例如,声明一个队列并指明服务器不发送任何响应。请使用:
channel.queueDeclareNoWait(queueName, true, false, false, null);
这个非等待版本更加有效,但是提供了更低的安全保证,比如,它们更依赖与心跳机制来检测操作的失败。当有疑问的时候还是从标准版本开始,这个非等待版本只在具有高拓扑(队列,绑定)才需要。
可以显式的删除一个队列或者交换:
channel.queueDelete("queue-name")
只有队列为空时,才删除队列:
channel.queueDelete("queue-name", false, true)
或者队列没有被任何消费者使用过:
channel.queueDelete("queue-name", true, false)
一个队列可以被清除:(队列中的所有消息被删除)
channel.queuePurge("queue-name")
可以发布一个消息到一个交换,使用:
byte[] messageBodyBytes = "Hello, world!".getBytes();
channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);
channel.basicPublish(exchangeName, routingKey, null, messageBodyBytes);
代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
在管理界面可以看到我们发布的消息:
为了更好的控制,可以使用重载变体来指定强制标志,或者使用预先设置的消息属性来发送消息:
channel.basicPublish(exchangeName, routingKey, mandatory,
MessageProperties.PERSISTENT_TEXT_PLAIN,
messageBodyBytes);
MessageProperties.PERSISTENT_TEXT_PLAIN,
messageBodyBytes);
代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_overload {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
// 第一个参数交换名称,第二个参数,路由密钥,第三个参数是否强制(mandatory=true|false)发布消息,第四个参数发布消息携带的消息属性,第五个参数消息体
channel.basicPublish(EXCHANGETEST, ROUTING, true, MessageProperties.PERSISTENT_TEXT_PLAIN, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_overload {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
// 第一个参数交换名称,第二个参数,路由密钥,第三个参数是否强制(mandatory=true|false)发布消息,第四个参数发布消息携带的消息属性,第五个参数消息体
channel.basicPublish(EXCHANGETEST, ROUTING, true, MessageProperties.PERSISTENT_TEXT_PLAIN, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
这将发送一个带有传递模式2(持久),优先级(1),和内容类型为text/plain,您可以使用Builder类,来构建自己的消息属性对象,该类提供了许多你喜欢的属性,例如:
channel.basicPublish(exchangeName, routingKey,
new AMQP.BasicProperties.Builder()
.contentType("text/plain")
.deliveryMode(2)
.priority(1)
.userId("bob")
.build()),
messageBodyBytes);
new AMQP.BasicProperties.Builder()
.contentType("text/plain")
.deliveryMode(2)
.priority(1)
.userId("bob")
.build()),
messageBodyBytes);
代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_builder {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST01";
// 用于绑定的key
private static final String ROUTING = "ROUTING01";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST01";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING,true,
new AMQP.BasicProperties.Builder()
.contentType("text/plain")
.deliveryMode(2)
.priority(1)
.build(),
message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_builder {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST01";
// 用于绑定的key
private static final String ROUTING = "ROUTING01";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST01";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "Hello World".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING,true,
new AMQP.BasicProperties.Builder()
.contentType("text/plain")
.deliveryMode(2)
.priority(1)
.build(),
message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
带有超时时间和自定义头的消息发送:
Map headers = new HashMap();
headers.put("latitude", 51.5252949);
headers.put("longitude", -0.0905493);
channel.basicPublish(exchangeName, routingKey,
new AMQP.BasicProperties.Builder()
.headers(headers)
.build()),
messageBodyBytes);
channel.basicPublish(exchangeName, routingKey,
new AMQP.BasicProperties.Builder()
.expiration("60000")
.build()),
messageBodyBytes);
headers.put("latitude", 51.5252949);
headers.put("longitude", -0.0905493);
channel.basicPublish(exchangeName, routingKey,
new AMQP.BasicProperties.Builder()
.headers(headers)
.build()),
messageBodyBytes);
channel.basicPublish(exchangeName, routingKey,
new AMQP.BasicProperties.Builder()
.expiration("60000")
.build()),
messageBodyBytes);
代码如下:
package com.refrain.rabbitmq; import com.rabbitmq.client.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; /** * @Program: rabbitMq_connection * @Auther: lijiamin * @Date: 18-8-3 15:31 * @Description: 连接到RabbitMq */ public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_builder { // 连接rabbitmq的用户名 private static final String USERNAME = "guest"; // 连接rabbitmq的密码 private static final String PASSWORD = "guest"; // 连接rabbitmq的虚拟主机 private static final String VIRTUALHOST = "/"; // 连接rabbitmq的主机名称 private static final String HOSTNAME = "127.0.0.1"; // 连接rabbitmq的端口 private static final int PORT = 5672; // 使用交易的名称 private static final String EXCHANGETEST = "EXCHANGETEST02"; // 用于绑定的key private static final String ROUTING = "ROUTING02"; // 声明队列名称,方便队列共享 private static final String QUEUETEST = "QUEUETEST02"; /** * @param args */ public static void main(String[] args) { /*使用给定的参数连接到rabbitmq*/ // 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例 ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setUsername(USERNAME); connectionFactory.setPassword(PASSWORD); connectionFactory.setVirtualHost(VIRTUALHOST); connectionFactory.setHost(HOSTNAME); connectionFactory.setPort(PORT); // 第二步:创建连接 Connection connection = null; try { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); // 声明一个交易 channel.exchangeDeclare(EXCHANGETEST, "direct", true); // 声明一个队列 channel.queueDeclare(QUEUETEST, true, false, false, null); channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING); byte [] message = "test".getBytes(); Map
import com.rabbitmq.client.*; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; /** * @Program: rabbitMq_connection * @Auther: lijiamin * @Date: 18-8-3 15:31 * @Description: 连接到RabbitMq */ public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message_use_builder { // 连接rabbitmq的用户名 private static final String USERNAME = "guest"; // 连接rabbitmq的密码 private static final String PASSWORD = "guest"; // 连接rabbitmq的虚拟主机 private static final String VIRTUALHOST = "/"; // 连接rabbitmq的主机名称 private static final String HOSTNAME = "127.0.0.1"; // 连接rabbitmq的端口 private static final int PORT = 5672; // 使用交易的名称 private static final String EXCHANGETEST = "EXCHANGETEST02"; // 用于绑定的key private static final String ROUTING = "ROUTING02"; // 声明队列名称,方便队列共享 private static final String QUEUETEST = "QUEUETEST02"; /** * @param args */ public static void main(String[] args) { /*使用给定的参数连接到rabbitmq*/ // 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例 ConnectionFactory connectionFactory = new ConnectionFactory(); connectionFactory.setUsername(USERNAME); connectionFactory.setPassword(PASSWORD); connectionFactory.setVirtualHost(VIRTUALHOST); connectionFactory.setHost(HOSTNAME); connectionFactory.setPort(PORT); // 第二步:创建连接 Connection connection = null; try { connection = connectionFactory.newConnection(); Channel channel = connection.createChannel(); // 声明一个交易 channel.exchangeDeclare(EXCHANGETEST, "direct", true); // 声明一个队列 channel.queueDeclare(QUEUETEST, true, false, false, null); channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING); byte [] message = "test".getBytes(); Mapheaders = new HashMap<>(); headers.put("zhangsan", "zhangsan"); headers.put("lisi", "lisi"); channel.basicPublish(EXCHANGETEST, ROUTING,true, new AMQP.BasicProperties.Builder() .contentType("text/plain") .headers(headers) .expiration("60000") .deliveryMode(2) .priority(1) .build(), message); System.out.println("发布成功"); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } } headers = new HashMap<>(); headers.put("zhangsan", "zhangsan"); headers.put("lisi", "lisi"); channel.basicPublish(EXCHANGETEST, ROUTING,true, new AMQP.BasicProperties.Builder() .contentType("text/plain") .headers(headers) .expiration("60000") .deliveryMode(2) .priority(1) .build(), message); System.out.println("发布成功"); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } }
管理界面可以看到消息的头和超时时间:
作为 经验法则,在线程之间共享通道实例是必须避免的,应用程序更倾向与每个通道开启一个线程。而不是多线程之间通道共享。
虽然一些通道上的操作是安全的并发调用,但是,有一些不是,并且会导致不正确的帧交织,双确认等。
共享通道的并发发布会导致不正确的帧交织,会触发连接级别的协议异常并立即通过代理关闭连接。因此,在应用程序代码中要求显式的同步。
必须在关键部分调用通道,在线程之间共享通道会妨碍服务器发布确认。在共享通道上并发发布最好完全避免,例如,为每个线程开启一个通道。
可以使用通道池来避免在共享通道上的并发发布。一旦一个线程使用了一个通道,它将返回到这个通道池中,使得该通道可用于其它线程。通道池被认为是一种特定的同步解决方案。建议使用现有的通道池库代替本地解决方案。例如,Spring AMQP,它带有一个随时可用的通道池特性。
通道消耗资源,并且在大多数情况下,应用程序很少需要在同一个JVM中开启几百个通道。
最有效的接收消息的方式是在消费者接口设置订阅,当消息到达的时候会被自动传递,而不是必须显式的请求。
当调用与消费者相关的API方法时,私人订阅总是被它的消费者标签引用,一个消费者标签是一个消费者的标识符,这个标签可以有客户端或者服务器生成。为了让RabbitMq生成一个节点范围的唯一标签。消费者标签被用来取消消费者。
不同的消费者实例必须有不同的消费者标签。在一个连接上有重复的消费者标签是被强烈劝阻的。并且会导致当消费者被监控的时候自动恢复连接和监控数据混乱的问题。
实现一个消费者最简单的方法是使用DefaultConsumer子类,这个子类的对象,可以在basicConsume上传递以设置订阅。
代码如下:
生产者:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消费者:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_subscribe_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 第一个参数是队列名称,第二个参数是是否自动确认消息传达(如果为true:消息一旦传递,服务器会考虑自动确认,为false服务器期望在代码中显式的确认(例如:basicACK方法)。),第三个参数是消费者标签,可以在客户端指定,也可以不指定由服务器生成,第四个参数是消费者的匿名内部类
channel.basicConsume(QUEUETEST, false, "myTag",
new DefaultConsumer(channel) {
// 第一个参数是消费者标签,第二个参数是包含发布消息的交换以及路由密钥等
// 第三个参数是发布消息的属性,第四个参数是消息体
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者标签:" + consumerTag);
System.out.println("路由密钥:" + envelope.getRoutingKey());
System.out.println("交换:" + envelope.getExchange());
System.out.println("传递标签:" + envelope.getDeliveryTag());
System.out.println("内容类型:" + properties.getContentType());
System.out.println("过期时间:" + properties.getExpiration());
System.out.println("消息内容:" + new String(body));
// 确认接收一个或者几个消息,第一个参数是传递标签,第二个参数如果为true,表示传递所有消息并包含传递的标签,如果为false,则只包含传递的标签。
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_subscribe_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 第一个参数是队列名称,第二个参数是是否自动确认消息传达(如果为true:消息一旦传递,服务器会考虑自动确认,为false服务器期望在代码中显式的确认(例如:basicACK方法)。),第三个参数是消费者标签,可以在客户端指定,也可以不指定由服务器生成,第四个参数是消费者的匿名内部类
channel.basicConsume(QUEUETEST, false, "myTag",
new DefaultConsumer(channel) {
// 第一个参数是消费者标签,第二个参数是包含发布消息的交换以及路由密钥等
// 第三个参数是发布消息的属性,第四个参数是消息体
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("消费者标签:" + consumerTag);
System.out.println("路由密钥:" + envelope.getRoutingKey());
System.out.println("交换:" + envelope.getExchange());
System.out.println("传递标签:" + envelope.getDeliveryTag());
System.out.println("内容类型:" + properties.getContentType());
System.out.println("过期时间:" + properties.getExpiration());
System.out.println("消息内容:" + new String(body));
// 确认接收一个或者几个消息,第一个参数是传递标签,第二个参数如果为true,表示传递所有消息并包含传递的标签,如果为false,则只包含传递的标签。
channel.basicAck(envelope.getDeliveryTag(), false);
}
});
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消费者控制台运行信息:
消费者标签:amq.ctag-wN--5CcbOhMbPQPZIoCk9g
路由密钥:ROUTING
交换:EXCHANGETEST
传递标签:1
内容类型:null
超时时间:null
消息内容:正在学习RabbitMq…
管理页面:可以看到消费者信息:
更复杂的消费者需要覆盖更多的方法,特别是当通道和连接关闭的时候handleSingnal被调用。而handleConsumeOk则是在该消费者被调用之前其它任何回调传递一个消费者标签。
消费者还可以分别实现显式和隐式取消通知的handleCancleOk和handleCancle方法。
可以显式的取消一个消费者,使用:
channel.basicCancel(consumerTag);
为了显式的检索消息,使用Channel.basicGet方法,返回值是一个GetResponse的实例,就可以从中提取(extracted)标题信息(属性),和消息正文。
代码如下:
消息生产者:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_publish_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.basicPublish(EXCHANGETEST, ROUTING, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
消息消费者:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.EventListener;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_retrieve_individual_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 检索单个消息
GetResponse response = channel.basicGet(QUEUETEST, false);
if(null == response) {
System.out.println("没有消息哦");
} else {
BasicProperties properties = response.getProps();
System.out.println("消息属性-内容类型:" + properties.getContentType());
System.out.println("消息属性-过期时间:" + properties.getExpiration());
Envelope envelope = response.getEnvelope();
System.out.println("信封-传递标签:" + envelope.getDeliveryTag());
System.out.println("信封-交换:" + envelope.getExchange());
System.out.println("信封-路由密钥:" + envelope.getRoutingKey());
byte [] message = response.getBody();
System.out.println("消息体:" + new String(message));
// 由于指定了autoACK=false所以需要在代码中显式的确认消息已经被接收。
channel.basicAck(envelope.getDeliveryTag(), false);
}
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.EventListener;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_retrieve_individual_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 检索单个消息
GetResponse response = channel.basicGet(QUEUETEST, false);
if(null == response) {
System.out.println("没有消息哦");
} else {
BasicProperties properties = response.getProps();
System.out.println("消息属性-内容类型:" + properties.getContentType());
System.out.println("消息属性-过期时间:" + properties.getExpiration());
Envelope envelope = response.getEnvelope();
System.out.println("信封-传递标签:" + envelope.getDeliveryTag());
System.out.println("信封-交换:" + envelope.getExchange());
System.out.println("信封-路由密钥:" + envelope.getRoutingKey());
byte [] message = response.getBody();
System.out.println("消息体:" + new String(message));
// 由于指定了autoACK=false所以需要在代码中显式的确认消息已经被接收。
channel.basicAck(envelope.getDeliveryTag(), false);
}
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
运行信息:
消息属性-内容类型:null
消息属性-过期时间:null
信封-传递标签:1
信封-交换:EXCHANGETEST
信封-路由密钥:ROUTING
消息体:正在学习RabbitMq…
如果一条被发布的消息带有强制标签设置,但是没有被路由到,这个代理将返回发送消息的客户端也就是消息生产者所在的客户端。
RabbitMQ中监听器有ReturnListener、ConfirmListener、ShutdownListener,本练习中使用ReturnListener,在发布消息时设置mandatory等于true,监听消息是否有相匹配的队列,没有时ReturnListener将执行handleReturn方法,消息将返给发送者
channel.basicPublish(EXCHANGETEST, ROUTING, true, MessageProperties.PERSISTENT_TEXT_PLAIN, message);
为了像一些返回语句被通知一样,客户端需要实现ReturnListener接口,并且调用Channel.addReturnListener方法,如果客户端没有为一个特定的通道配置一个监听器。那么,与这个发布消息相关的返回消息将被悄悄丢弃。
例如:客户端发布一个消息,它将强制标志设置为不绑定队列的直接类型的交换,则调用返回监听器。
代码如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_handle_unroutable_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("返回码:" + replyCode);
System.out.println("返回内容:" + replyText);
System.out.println("交换:" + exchange);
System.out.println("路由密钥:" + routingKey);
System.out.println("发送消息的属性:" + properties);
System.out.println("消息体:" + new String(body));
}
});
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, "", true, false, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_handle_unroutable_message {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("返回码:" + replyCode);
System.out.println("返回内容:" + replyText);
System.out.println("交换:" + exchange);
System.out.println("路由密钥:" + routingKey);
System.out.println("发送消息的属性:" + properties);
System.out.println("消息体:" + new String(body));
}
});
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, "", true, false, null, message);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}
运行信息:
返回码:312
返回内容:NO_ROUTE
交换:EXCHANGETEST
路由密钥:
发送消息的属性:#contentHeader
消息体:正在学习RabbitMq…
这个AQMP的连接和通道共享管理网络请求失败,内部失败,以及显式的本地停机的普通方法
这个AQMP的连接和通道有以下生命周期状态:
open:打开状态,意思就是这个对象待使用。
Closing:正在关闭状态,意思就是这个对象已经显式的被通知本地停机。已经对任何支持的下层对象发出关闭请求。并等待停机过程的完成。
Closed:关闭状态,意思就是,这个对象已经收到来自任何下层的对象的所有停机完成的通知,因此,它已经关闭了自己。
这个对象总是以关闭状态结束,不管关闭的原因是什么。比如,一个应用程序请求,内部客户端库失败,
远程网络请求或者网络失败。
这个AQMP连接和通道有以下与停机相关的方法:
addShutdownListener(ShutdownListener listener) 和removeShutdownListener(ShutdownListener listener),为了管理这些监听器,当这个对象被转换为关闭状态时,这些监听器被激发。请注意,为一个已经关闭的对象添加addShutdownListener监听器,监听器将立即激发。
getCloseReason()获取关闭原因:允许调查对象关闭的原因是什么。
IsOpen():用于测试这个对象是否被打开。
close(int closeCode, String closeMessage):显式的通知这个对象关闭。
关于监听器的简单用法如下:
package com.refrain.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_shutdown_listener {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) throws IOException {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, ROUTING, true, false, null, message);
connection.addShutdownListener(new ShutdownListener() {
@Override
public void shutdownCompleted(ShutdownSignalException cause) {
// 如果指示连接错误则返回true,如果指示通道错误则返回false
if(cause.isHardError()) {
Connection conn = (Connection) cause.getReference();
System.out.println("获取连接的引用:" + conn);
// 如果此异常是由显式应用程序引起的则返回true,如果来源于代理或者可检测的非故意的应用程序的失败,则返回false
if(cause.isInitiatedByApplication()) {
Method method = cause.getReason();
System.out.println("协议方法名称:" + method.protocolMethodName());
}
} else {
Channel chan = (Channel) cause.getReference();
System.out.println("获取通道的引用:" + chan);
Method method = cause.getReason();
System.out.println("协议方法名称:" + method.protocolMethodName());
}
}
});
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
if(null != connection) {
connection.close();
}
}
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_shutdown_listener {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) throws IOException {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
channel.queueDeclare(QUEUETEST, true, false, false, null);
channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, ROUTING, true, false, null, message);
connection.addShutdownListener(new ShutdownListener() {
@Override
public void shutdownCompleted(ShutdownSignalException cause) {
// 如果指示连接错误则返回true,如果指示通道错误则返回false
if(cause.isHardError()) {
Connection conn = (Connection) cause.getReference();
System.out.println("获取连接的引用:" + conn);
// 如果此异常是由显式应用程序引起的则返回true,如果来源于代理或者可检测的非故意的应用程序的失败,则返回false
if(cause.isInitiatedByApplication()) {
Method method = cause.getReason();
System.out.println("协议方法名称:" + method.protocolMethodName());
}
} else {
Channel chan = (Channel) cause.getReference();
System.out.println("获取通道的引用:" + chan);
Method method = cause.getReason();
System.out.println("协议方法名称:" + method.protocolMethodName());
}
}
});
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
} finally {
if(null != connection) {
connection.close();
}
}
}
}
运行信息如下:
发布成功
获取连接的引用:amqp://[email protected]:5672/
协议方法名称:connection.close
对于生产环境的代码,不推荐使用通道和连接的isOpen方法。因为方法的返回值依赖于停机原因的存在,下面的代码展示了这种情况:
package com.refrain.rabbitmq;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_use_isOpen {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
//channel.queueDeclare(QUEUETEST, true, false, false, null);
//channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, ROUTING, true,null, message);
brokenMethod(channel);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
private static void brokenMethod(Channel channel) {
// 如果通道处于打开状态则返回true否则返回false(不推荐使用连接和通道对象的isOpen方法,因为这个方法的返回值依赖于停机原因的存在)
// 下面是源码
/*@Override
private volatile ShutdownSignalException shutdownCause = null;
public boolean isOpen() {
synchronized(this.monitor) {
return this.shutdownCause == null;
}*/
if(channel.isOpen()) {
System.out.println("通道处于打开状态");
// 这里的代码依赖于通道处于打开状态,然而通道的状态是可能会发生变化的,在调用isOpen方法和basicQos方法之间。
try {
// 参数:服务器将传送最大数量的消息
channel.basicQos(1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Program: rabbitMq_connection
* @Auther: lijiamin
* @Date: 18-8-3 15:31
* @Description: 连接到RabbitMq
*/
public class ConnectRabbitMq_UsingExchangeAndQueue_use_isOpen {
// 连接rabbitmq的用户名
private static final String USERNAME = "guest";
// 连接rabbitmq的密码
private static final String PASSWORD = "guest";
// 连接rabbitmq的虚拟主机
private static final String VIRTUALHOST = "/";
// 连接rabbitmq的主机名称
private static final String HOSTNAME = "127.0.0.1";
// 连接rabbitmq的端口
private static final int PORT = 5672;
// 使用交易的名称
private static final String EXCHANGETEST = "EXCHANGETEST";
// 用于绑定的key
private static final String ROUTING = "ROUTING";
// 声明队列名称,方便队列共享
private static final String QUEUETEST = "QUEUETEST";
/**
* @param args
*/
public static void main(String[] args) {
/*使用给定的参数连接到rabbitmq*/
// 第一步:构造工厂实例;ConnectionFactory是用于构造connection实例的工厂类,因此,要连接到rabbitmq,首先要创建工厂实例
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setUsername(USERNAME);
connectionFactory.setPassword(PASSWORD);
connectionFactory.setVirtualHost(VIRTUALHOST);
connectionFactory.setHost(HOSTNAME);
connectionFactory.setPort(PORT);
// 第二步:创建连接
Connection connection = null;
try {
connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
// 声明一个交易
channel.exchangeDeclare(EXCHANGETEST, "direct", true);
// 声明一个队列
//channel.queueDeclare(QUEUETEST, true, false, false, null);
//channel.queueBind(QUEUETEST, EXCHANGETEST, ROUTING);
byte [] message = "正在学习RabbitMq...".getBytes();
// mandatory如果为true,则会监听是否有相匹配的队列,没有时则调用ReturnListener监听器
channel.basicPublish(EXCHANGETEST, ROUTING, true,null, message);
brokenMethod(channel);
System.out.println("发布成功");
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
private static void brokenMethod(Channel channel) {
// 如果通道处于打开状态则返回true否则返回false(不推荐使用连接和通道对象的isOpen方法,因为这个方法的返回值依赖于停机原因的存在)
// 下面是源码
/*@Override
private volatile ShutdownSignalException shutdownCause = null;
public boolean isOpen() {
synchronized(this.monitor) {
return this.shutdownCause == null;
}*/
if(channel.isOpen()) {
System.out.println("通道处于打开状态");
// 这里的代码依赖于通道处于打开状态,然而通道的状态是可能会发生变化的,在调用isOpen方法和basicQos方法之间。
try {
// 参数:服务器将传送最大数量的消息
channel.basicQos(1);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
对于生产环境的代码,不推荐使用通道和连接的isOpen方法。因为方法的返回值依赖于停机原因的存在。相反的,我们应该在写业务逻辑的时候,正常的忽略这种检查,如果代码在执行期间,连接的通道被关闭。将抛出一个对象状态不明确的停机指示异常。当代理意外的关闭了这个连接的时候,我们也应该捕获由SocketException引起的IO异常。
例如:
public void validMethod(Channel channel)
{
try {
...
channel.basicQos(1);
} catch (ShutdownSignalException sse) {
// possibly check if channel was closed(如果通道被关闭可能会检测)
// by the time we started action and reasons for
// closing it
...
} catch (IOException ioe) {
// check why connection was closed(检查为什么连接被关闭)
...
}
}
{
try {
...
channel.basicQos(1);
} catch (ShutdownSignalException sse) {
// possibly check if channel was closed(如果通道被关闭可能会检测)
// by the time we started action and reasons for
// closing it
...
} catch (IOException ioe) {
// check why connection was closed(检查为什么连接被关闭)
...
}
}
消费者连接池:
默认情况下,消费者线程可以自动分配到一个新的 ExecutorService线程池。如果需要更大的控制,则在new Connection方法上提供一个线程池。因此,使用线程池来代替正常分配,下面代码是一个示例,其中,提供了一个比正常分配更大的线程池。
示例代码如下:
ExecutorService es = Executors.newFixedThreadPool(20);
Connection conn = factory.newConnection(es);
Connection conn = factory.newConnection(es);
Executors和ExcecutorService在java.util.concurrent包中。
当连接关闭的时候,默认的ExcecutorService将被关闭。但是用户自定义的ExcecutorService将不被关闭。客户端提供自定义的ExecutorService必须确保它通过调用shutdown()方法最终关闭。否则,这个线程池的线程可能会阻止JVM终端。
这个相同的ExcecutorService可能会在多个连接之间共享。或者在重新连接上串行重用,但是在ExceutorService关闭后就不能使用。
使用这个高级特性,它在消费者回调进程中存在一个严重瓶颈的问题应该被考虑。如果,没有消费者回调被执行或者不多,那么默认的分配将绰绰有余。
可以把这个地址数组放到newConnection()参数中,一个地址(Address)在带有Host和Port端口的组件的com.rabbitmq.client 包中是一个简单方便的类,例如:
Address[] addrArr = new Address[]{ new Address(hostname1, portnumber1), new Address(hostname2, portnumber2)};
Connection conn = factory.newConnection(addrArr);
Connection conn = factory.newConnection(addrArr);
在这个地址数组中,如果某一个连接失败,将试图连接其它的地址,这个连接将返回数组中成功连接(没有抛出异常)的第一个地址。这将等同于在连接工厂中重复的设置主机和端口号,每次去调用newConnection()方法,直到它们中有一个连接成功。
如果一个newConnection(es, addr)用到了ExecutorService,则线程池与第一次成功的连接的地址相关联。
Connection conn = factory.newConnection(addressResolver);
public interface AddressResolver {
List getAddresses() throws IOException;
}
public interface AddressResolver {
List getAddresses() throws IOException;
}
ConnectionFactory cf = new ConnectionFactory();
// set the heartbeat timeout to 60 seconds
cf.setRequestedHeartbeat(60);
// set the heartbeat timeout to 60 seconds
cf.setRequestedHeartbeat(60);
import com.google.appengine.api.ThreadManager;
ConnectionFactory cf = new ConnectionFactory();
cf.setThreadFactory(ThreadManager.backgroundThreadFactory());
ConnectionFactory cf = new ConnectionFactory();
cf.setThreadFactory(ThreadManager.backgroundThreadFactory());
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.useNio();
connectionFactory.useNio();
配置NIO参数:
connectionFactory.setNioParams(new NioParams().setNbIoThreads(4));
恢复连接:
许多应用程序的自动恢复过程遵循以下步骤:
Reconnect
Restore connection listeners
Re-open channels
Restore channel listeners
Restore channel basic.qos setting, publisher confirms and transaction settings
拓扑恢复包括为每个通道执行的以下操作:
Re-declare exchanges (except for predefined ones)
Re-declare queues
Recover all bindings
Recover all consumers
Recover all consumers
开启或禁用自动恢复连接:
ConnectionFactory factory = new ConnectionFactory();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
factory.setAutomaticRecoveryEnabled(true);
// connection that will recover automatically
Connection conn = factory.newConnection();
factory.setUsername(userName);
factory.setPassword(password);
factory.setVirtualHost(virtualHost);
factory.setHost(hostName);
factory.setPort(portNumber);
factory.setAutomaticRecoveryEnabled(true);
// connection that will recover automatically
Connection conn = factory.newConnection();
每隔多长时间自动恢复连接:
ConnectionFactory factory = new ConnectionFactory();
// attempt recovery every 10 seconds
factory.setNetworkRecoveryInterval(10000);
// attempt recovery every 10 seconds
factory.setNetworkRecoveryInterval(10000);
什么时候触发自动恢复连接?
1.在连接的I/O循环中引发I/O异常
2.socket读取操作超时
3.未检测到服务器心跳
4.在连接的I/O循环中抛出任何其他意外的异常
如果初始的客户端连接到RabbitMq节点失败,则自动连接恢复将不会自动启动,应用程序负责重试这些连接、记录失败的尝试、实现重试次数的限制。例如:
ConnectionFactory factory = new ConnectionFactory();
// configure various connection settings
try {
Connection conn = factory.newConnection();
} catch (java.net.ConnectException e) {
Thread.sleep(5000);
// apply retry logic
}
// configure various connection settings
try {
Connection conn = factory.newConnection();
} catch (java.net.ConnectException e) {
Thread.sleep(5000);
// apply retry logic
}
在一个可以恢复的连接和通道上注册一个或者多个恢复监听器是可以的。当连接恢复可用的时候。连接将返回newConnection或者createChannel。添加恢复监听器需要实现Recoverable接口:
addRecoveryListener
removeRecoveryListener
使用channel.basicPublish()方法发布的消息,当连接关闭的时候消息会丢失。连接恢复后,客户端不会将它们排队等待传递。为了确保发布的消息到达RabbitMq 应用程序,需要使用发布确认和连接失败的账户。
自动恢复连接有许多限制和有意的设计决策。应用程序开发者需要意识到这一点。
当手动确认被使用的时候,到RabbitMq的网络连接可能在消息传递和确认之间失败。
对于应用程序开发者来说,自动恢复连接应该是尽可能透明的。
ConnectionFactory factory = new ConnectionFactory();
cf.setExceptionHandler(customHandler);// 参数:自定义异常处理器
cf.setExceptionHandler(customHandler);// 参数:自定义异常处理器
客户端提供Micrometer support 和 Dropwizard Metrics 这两种形式的监控支持。
第一种方式:
ConnectionFactory connectionFactory = new ConnectionFactory();
MicrometerMetricsCollector metrics = new MicrometerMetricsCollector();
connectionFactory.setMetricsCollector(metrics);
...
metrics.getPublishedMessages(); // get Micrometer's Counter object
MicrometerMetricsCollector metrics = new MicrometerMetricsCollector();
connectionFactory.setMetricsCollector(metrics);
...
metrics.getPublishedMessages(); // get Micrometer's Counter object
第二种方式:
JmxMeterRegistry registry = new JmxMeterRegistry();
MicrometerMetricsCollector metrics = new MicrometerMetricsCollector(registry);
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setMetricsCollector(metrics);
MicrometerMetricsCollector metrics = new MicrometerMetricsCollector(registry);
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setMetricsCollector(metrics);
第一种方式:
ConnectionFactory connectionFactory = new ConnectionFactory();
StandardMetricsCollector metrics = new StandardMetricsCollector();
connectionFactory.setMetricsCollector(metrics);
...
metrics.getPublishedMessages(); // get Metrics' Meter object
StandardMetricsCollector metrics = new StandardMetricsCollector();
connectionFactory.setMetricsCollector(metrics);
...
metrics.getPublishedMessages(); // get Metrics' Meter object
第二种方式:
MetricRegistry registry = new MetricRegistry();
StandardMetricsCollector metrics = new StandardMetricsCollector(registry);
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setMetricsCollector(metrics);
JmxReporter reporter = JmxReporter
.forRegistry(registry)
.inDomain("com.rabbitmq.client.jmx")
.build();
reporter.start();
StandardMetricsCollector metrics = new StandardMetricsCollector(registry);
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setMetricsCollector(metrics);
JmxReporter reporter = JmxReporter
.forRegistry(registry)
.inDomain("com.rabbitmq.client.jmx")
.build();
reporter.start();
ConnectionFactory factory = new ConnectionFactory();
cf.setRequestedHeartbeat(5);
cf.setRequestedHeartbeat(5);
import com.rabbitmq.client.RpcClient;
RpcClient rpc = new RpcClient(channel, exchangeName, routingKey);
一旦创建了rpc就可以调用这些方法,发送远程请求。
byte[] primitiveCall(byte[] message);
String stringCall(String message)
Map mapCall(Map message)
Map mapCall(Object[] keyValuePairs)
String stringCall(String message)
Map mapCall(Map message)
Map mapCall(Object[] keyValuePairs)
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
factory.setPort(5671);
factory.useSslProtocol();
factory.setHost("localhost");
factory.setPort(5671);
factory.useSslProtocol();