yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make
gcc gcc-c++ kernel-devel m4 ncurses-devel tk tc xz
sudo yum install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlitedevel readline-devel tk-devel gcc make -y
下载rpm包
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-utils-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-static-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-common-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-devel-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/glibc-headers-2.17-55.el6.x86_64.rpm &
wget http://copr-be.cloud.fedoraproject.org/results/mosquito/myrepoel6/epel-6-x86_64/glibc-2.17-55.fc20/nscd-2.17-55.el6.x86_64.rpm &
安装rpm
sudo rpm -Uvh socat-1.7.3.2-1.1.el7.x86_64.rpm --force --nodeps
查看glibc版本
strings /lib64/libc.so.6 | grep GLIBC
安装
rpm -ivh erlang-18.3-1.el7.centos.x86_64.rpm
rpm -ivh socat-1.7.3.2-1.1.el7.x86_64.rpm --force --nodeps
rpm -ivh rabbitmq-server-3.6.5-1.noarch.rpm
# 开启管理界⾯
rabbitmq-plugins enable rabbitmq_management
# 修改默认配置信息
vim /usr/lib/rabbitmq/lib/rabbitmq_server-3.6.5/ebin/rabbit.app
# ⽐如修改密码、配置等等,例如:loopback_users 中的 <<"guest">>,只保留guest
service rabbitmq-server start # 启动服务
service rabbitmq-server stop # 停⽌服务
service rabbitmq-server restart # 重启服务
设置配置文件
cd /usr/share/doc/rabbitmq-server-3.6.5/
cp rabbitmq.config.example /etc/rabbitmq/rabbitmq.config
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
创建消息生产者
public class Producer {
static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//主机地址
connectionFactory.setHost("192.168.238.129");
//链接端口,默认5672
connectionFactory.setPort(5672);
//虚拟主机名称 默认guest
connectionFactory.setVirtualHost("/bbb");
//链接用户名,默认guest
connectionFactory.setUsername("aaa");
//链接密码,默认guest
connectionFactory.setPassword("aaa");
//创建链接
Connection connection = connectionFactory.newConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 师傅定义持久化队列
* 是否独占本次链接
* 是否在不适用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
String message = "你好,rabbitMQ";
/**
*交换机名称,默认Default Exchage
* 路由key,简单模式可以传递队列名称
* 消息其他属性
* 消息内容
*/
channel.basicPublish("",QUEUE_NAME,null,message.getBytes());
// 关闭资源
channel.close();
connection.close();
}
}
消息消费者
static final String QUEUE_NAME = "simple_queue";
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//主机地址
connectionFactory.setHost("192.168.238.129");
//链接端口,默认5672
connectionFactory.setPort(5672);
//虚拟主机名称 默认guest
connectionFactory.setVirtualHost("/bbb");
//链接用户名,默认guest
connectionFactory.setUsername("aaa");
//链接密码,默认guest
connectionFactory.setPassword("aaa");
//创建链接
Connection connection = connectionFactory.newConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
在这里插入代码片
Work Queues 与入门程序的 简单模式 相比,多了一个或一些消费端,多个消费端共同消费同一个队列中的消息。
应用场景:对于 任务过重或任务较多情况使用工作队列可以提高任务处理的速度。
链接工具类
public class ConnectionUtils {
public static Connection getConnection() throws IOException, TimeoutException {
//创建链接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//主机地址
connectionFactory.setHost("192.168.238.129");
//链接端口,默认5672
connectionFactory.setPort(5672);
//虚拟主机名称 默认guest
connectionFactory.setVirtualHost("/bbb");
//链接用户名,默认guest
connectionFactory.setUsername("aaa");
//链接密码,默认guest
connectionFactory.setPassword("aaa");
//创建链接
Connection connection = connectionFactory.newConnection();
return connection;
}
}
消息生产者
public class Producer {
static final String QUEUE_NAME = "work_queue";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
// 声明(创建)队列
/***
参数1:队列名称 *
参数2:是否定义持久化队列 *
参数3:是否独占本次连接 *
参数4:是否在不使用的时候自动删除队列 *
参数5:队列其它参数 */
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
for (int i = 1; i <= 30; i++) {
String message = "你好;rabbit!work模式--" + i;
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println("已发送消息:" + message);
}
// 关闭资源
channel.close();
connection.close();
}
}
消息消费者1
public class Consumer1 {
static final String QUEUE_NAME = Producer.QUEUE_NAME;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者1,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
**消息消费者2**
```python
public class Consumer2 {
static final String QUEUE_NAME = Producer.QUEUE_NAME;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者2,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
public class Producer {
static final String FANOUT_EXCHANGE = "fanout_exchange";
static final String FANOUT_QUEUE_NAME1 = "fanout_queue1";
static final String FANOUT_QUEUE_NAME2 = "fanout_queue2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
//声明交换机
/**
* 交换机名称
* 交换机类型 fanout,topic,direct,headers
*/
channel.exchangeDeclare(FANOUT_EXCHANGE, BuiltinExchangeType.FANOUT);
channel.queueDeclare(FANOUT_QUEUE_NAME1,true,false,false,null);
channel.queueDeclare(FANOUT_QUEUE_NAME2,true,false,false,null);
channel.queueBind(FANOUT_QUEUE_NAME1,FANOUT_EXCHANGE,"");
channel.queueBind(FANOUT_QUEUE_NAME2,FANOUT_EXCHANGE,"");
for (int i = 1; i <= 10; i++) {
String message = "你好;rabbit!work模式--" + i;
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(FANOUT_EXCHANGE, "", null, message.getBytes());
System.out.println("已发送消息:" + message);
}
// 关闭资源
channel.close();
connection.close();
}
}
消费者1
public class Consumer1 {
static final String QUEUE_NAME = Producer.FANOUT_QUEUE_NAME1;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者1,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
**消费者2**
```python
public class Consumer1 {
static final String QUEUE_NAME = Producer.FANOUT_QUEUE_NAME2;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者1,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
交换机需要与队列进行绑定,绑定之后;一个消息可以被多个消费者都收到
在编码上与 Publish/Subscribe发布与订阅模式 的区别是交换机的类型为:Direct,还有队列绑定交换机的时候需要指定routing key。
生产者
public class Producer {
static final String DIRECT_EXCHANGE = "direct_exchange";
static final String DIRECT_QUEUE_NAME1 = "direct_queue1";
static final String DIRECT_QUEUE_NAME2 = "direct_queue2";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
//声明交换机
/**
* 交换机名称
* 交换机类型 fanout,topic,direct,headers
*/
channel.exchangeDeclare(DIRECT_EXCHANGE, BuiltinExchangeType.DIRECT);
channel.queueDeclare(DIRECT_QUEUE_NAME1,true,false,false,null);
channel.queueDeclare(DIRECT_QUEUE_NAME2,true,false,false,null);
channel.queueBind(DIRECT_QUEUE_NAME1,DIRECT_EXCHANGE,"insert");
channel.queueBind(DIRECT_QUEUE_NAME2,DIRECT_EXCHANGE,"update");
for (int i = 1; i <= 10; i++) {
String message = "新增商品,路由模式,routing key insert" + i;
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(DIRECT_EXCHANGE, "insert", null, message.getBytes());
System.out.println("已发送消息:" + message);
}
for (int i = 1; i <= 10; i++) {
String message = "修改商品,路由模式,routing key update" + i;
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(DIRECT_EXCHANGE, "update", null, message.getBytes());
System.out.println("已发送消息:" + message);
}
// 关闭资源
channel.close();
connection.close();
}
}
消费者1
public class Consumer1 {
static final String QUEUE_NAME = Producer.DIRECT_QUEUE_NAME1;
static final String EXCHANGE_NAME = Producer.DIRECT_EXCHANGE;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"insert");
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者1,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
消费者2
public class Consumer2 {
static final String QUEUE_NAME = Producer.DIRECT_QUEUE_NAME2;
static final String EXCHANGE_NAME = Producer.DIRECT_EXCHANGE;
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
channel.queueBind(QUEUE_NAME,EXCHANGE_NAME,"update");
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者2,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(QUEUE_NAME, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
public class Producer {
static final String TOPIC_EXCHANGE = "topic_exchange";
static final String TOPIC_QUEUE_ALL = "topic_queue_all";
static final String TOPIC_QUEUE_UPDATE_INSERT = "topic_queue_update_insert";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = ConnectionUtils.getConnection();
// 创建频道
Channel channel = connection.createChannel();
//声明交换机
/**
* 交换机名称
* 交换机类型 fanout,topic,direct,headers
*/
channel.exchangeDeclare(TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
String message = "新增商品,路由模式,topic key item.insert";
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(TOPIC_EXCHANGE, "item.insert", null, message.getBytes());
System.out.println("已发送消息:" + message);
message = "修改商品,路由模式,topic key item.update";
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(TOPIC_EXCHANGE, "item.update", null, message.getBytes());
System.out.println("已发送消息:" + message);
message = "删除商品,路由模式,topic key item.delete";
/***
* 参数1:交换机名称,如果没有指定则使用默认Default Exchage *
* 参数2:路由key,简单模式可以传递队列名称 *
* 参数3:消息其它属性 *
* 参数4:消息内容 */
channel.basicPublish(TOPIC_EXCHANGE, "item.delete", null, message.getBytes());
System.out.println("已发送消息:" + message);
// 关闭资源
channel.close();
connection.close();
}
}
消费者1
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(Producer.TOPIC_QUEUE_ALL, true, false, false, null);
channel.queueBind(Producer.TOPIC_QUEUE_ALL, Producer.TOPIC_EXCHANGE, "item.*");
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者1,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(Producer.TOPIC_QUEUE_ALL, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
消费者2
public class Consumer2 {
public static void main(String[] args) throws IOException, TimeoutException {
//创建链接
Connection connection = ConnectionUtils.getConnection();
//创建频道
Channel channel = connection.createChannel();
//声明交换机
channel.exchangeDeclare(Producer.TOPIC_EXCHANGE, BuiltinExchangeType.TOPIC);
//申明队列
/**
*队列名称
* 是否定义持久化队列
* 是否独占本次链接
* 是否在不使用的时候自动删除队列
* 队列其他参数
*/
channel.queueDeclare(Producer.TOPIC_QUEUE_UPDATE_INSERT, true, false, false, null);
channel.queueBind(Producer.TOPIC_QUEUE_UPDATE_INSERT,Producer.TOPIC_EXCHANGE,"item.update");
channel.queueBind(Producer.TOPIC_QUEUE_UPDATE_INSERT,Producer.TOPIC_EXCHANGE,"item.insert");
//消息
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
/**
* consumerTag 消息者标签,在channel.basicConsume时候可以指定
* envelope 消息包的内容,可从中获取消息id,消息routingkey,交换机,消息和重 传标志(收到消息失败后是否需要重新发送)
* properties 属性信息
* body 消息
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//路由key
System.out.println("路由key为:" + envelope.getRoutingKey());
//交换机
System.out.println("交换机为:" + envelope.getExchange());
//消息id
System.out.println("消息id为:" + envelope.getDeliveryTag());
//收到的消息
System.out.println("消费者2,接收到的消息为:" + new String(body, "utf-8"));
}
};
//监听消息
/**
*队列名称
* 是否自动确认,设置为true为表示消息接收到自动向mq回复接收到了,mq接收到回复 会删除消息,设置为false则需要手动确认
* 消息接收到后回调
*/
channel.basicConsume(Producer.TOPIC_QUEUE_UPDATE_INSERT, true, defaultConsumer);
// 不关闭资源,应该一直监听消息
}
}
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
rabbitmq:
host: 192.168.238.129
port: 5672
virtual-host: /bbb
username: aaa
password: aaa
@Configuration
public class RabbitMQConfig {
//交换机名称
public static final String ITEM_TOPIC_EXCHANGE = "springboot_item_topic_exchange";
//队列名称
public static final String ITEM_QUEUE = "springboot_item_queue";
//声明交换机
@Bean("itemTopicExchange")
public Exchange topicExchange() {
return ExchangeBuilder.topicExchange(ITEM_TOPIC_EXCHANGE).durable(true).build();
}
//申明队列
@Bean("itemQueue")
public Queue itemQueue() {
return QueueBuilder.durable(ITEM_QUEUE).build();
}
//判断队列和交换机
@Bean
public Binding itemQueueExchange(@Qualifier("itemQueue") Queue queue, @Qualifier("itemTopicExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("item.#").noargs();
}
}
@SpringBootTest
public class SpringbootRabbitmqApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void contextLoads() {
rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE,"item.insert", "商品新增,routing key 为item.insert");
rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE, "item.update", "商品修改,routing key 为item.update");
rabbitTemplate.convertAndSend(RabbitMQConfig.ITEM_TOPIC_EXCHANGE, "item.delete", "商品删除,routing key 为item.delete");
}
}
@Component
public class MyListener {
/**
*监听某个队列的消息
*/
@RabbitListener(queues = "springboot_item_queue")
public void myListener1(String message) {
System.out.println("消费者接收到的消息为:" + message);
}
}
消息从 producer 到 exchange 则会返回一个 confirmCallback
确认模式开启:ConnectionFactory中开启publisher-confirms="true"
在rabbitTemplate定义ConfirmCallBack回调函数
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
/**
*
* @param correlationData 相关配置信息
* @param ack exchange交换机 是否成功收到了消息。true 成功,false代表失败
* @param cause 失败原因
*/
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
System.out.println("confirm方法被执行了。。。");
if (ack) {
System.out.println("成功接收消息:" + cause);
} else {
System.out.println("接收消息失败:" + cause);
//业务处理
}
}
});
rabbitTemplate.convertAndSend("test_exchange_confirm22", "confirm", "message confirm....");
消息从 exchange–>queue 投递失败则会返回一个 returnCallback
/**
* 回退模式: 当消息发送给Exchange后,Exchange路由到Queue失败是 才会执行 ReturnCallBack
* 步骤:
* 1. 开启回退模式:publisher-returns="true"
* 2. 设置ReturnCallBack
* 3. 设置Exchange处理消息失败的模式:setMandatory
* 1. 如果消息没有路由到Queue,则丢弃消息(默认)
* 2. 如果消息没有路由到Queue,返回给消息发送方ReturnCallBack
*/
@Test
public void testReturn() {
//设置交换机处理失败消息的模式
rabbitTemplate.setMandatory(true);
//2.设置ReturnCallBack
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback() {
/**
*
* @param message 消息对象
* @param replyCode 错误码
* @param replyText 错误信息
* @param exchange 交换机
* @param routingKey 路由键
*/
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println("return 执行了....");
System.out.println(message);
System.out.println(replyCode);
System.out.println(replyText);
System.out.println(exchange);
System.out.println(routingKey);
//处理
}
});
//3. 发送消息
rabbitTemplate.convertAndSend("test_exchange_confirm", "confirm", "message confirm....");
}
@Component
public class AckListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliverTag = message.getMessageProperties().getDeliveryTag();
try {
System.out.println(new String(message.getBody()));
System.out.println("处理业务逻辑");
int i = 3/0;//模拟业务处理异常
channel.basicAck(deliverTag, true);
} catch (Exception e) {
e.printStackTrace();
//拒绝签收
//requeue:true:表示重回队列
channel.basicNack(deliverTag, true, true);
// channel.basicReject(deliverTag, true);
}
}
}
@Component
public class QosListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
Thread.sleep(1000);
//1.获取消息
System.out.println(new String(message.getBody()));
//2. 处理业务逻辑
//3. 签收
channel.basicAck(message.getMessageProperties().getDeliveryTag(),true);
}
}
<!--ttl-->
<rabbit:queue name="test_queue_ttl" id="test_queue_ttl">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="100000" value-type="java.lang.Integer"></entry>
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:topic-exchange name="test_exchange_ttl">
<rabbit:bindings>
<rabbit:binding pattern="ttl.#" queue="test_queue_ttl"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
/**
* TTL:过期时间
* 1. 队列统一过期
*
* 2. 消息单独过期
*
*
* 如果设置了消息的过期时间,也设置了队列的过期时间,它以时间短的为准。
* 队列过期后,会将队列所有消息全部移除。
* 消息过期后,只有消息在队列顶端,才会判断其是否过期(移除掉)
*
*/
@Test
public void testTtl() {
// for (int i = 0; i < 10; i++) {
// // 发送消息
// rabbitTemplate.convertAndSend("test_exchange_ttl", "ttl.hehe", "message ttl....");
// }
// // 消息后处理对象,设置一些消息的参数信息
MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
//1.设置message的信息
message.getMessageProperties().setExpiration("5000");//消息的过期时间
//2.返回该消息
return message;
}
};
// //消息单独过期
// rabbitTemplate.convertAndSend("test_exchange_ttl", "ttl.hehe", "message ttl....", messagePostProcessor);
for (int i = 0; i < 10; i++) {
if(i == 5){
//消息单独过期
rabbitTemplate.convertAndSend("test_exchange_ttl", "ttl.hehe", "message ttl....",messagePostProcessor);
}else{
//不过期的消息
rabbitTemplate.convertAndSend("test_exchange_ttl", "ttl.hehe", "message ttl....");
}
}
}
<!--
1. 声明正常的队列(test_queue_dlx)和交换机(test_exchange_dlx)
-->
<rabbit:queue name="test_queue_dlx" id="test_queue_dlx">
<!--3. 正常队列绑定死信交换机-->
<rabbit:queue-arguments>
<!--3.1 x-dead-letter-exchange:死信交换机名称-->
<entry key="x-dead-letter-exchange" value="exchange_dlx" />
<!--3.2 x-dead-letter-routing-key:发送给死信交换机的routingkey-->
<entry key="x-dead-letter-routing-key" value="dlx.hehe" />
<!--4.1 设置队列的过期时间 ttl-->
<entry key="x-message-ttl" value="10000" value-type="java.lang.Integer" />
<!--4.2 设置队列的长度限制 max-length -->
<entry key="x-max-length" value="10" value-type="java.lang.Integer" />
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:topic-exchange name="test_exchange_dlx">
<rabbit:bindings>
<rabbit:binding pattern="test.dlx.#" queue="test_queue_dlx"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
<!--
2. 声明死信队列(queue_dlx)和死信交换机(exchange_dlx)
-->
<rabbit:queue name="queue_dlx" id="queue_dlx"></rabbit:queue>
<rabbit:topic-exchange name="exchange_dlx">
<rabbit:bindings>
<rabbit:binding pattern="dlx.#" queue="queue_dlx"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
/**
* 发送测试死信消息:
* 1. 过期时间
* 2. 长度限制
* 3. 消息拒收
*/
@Test
public void testDlx(){
//1. 测试过期时间,死信消息
// rabbitTemplate.convertAndSend("test_exchange_dlx","test.dlx.haha","我是一条消息,我会死吗?");
//2. 测试长度限制后,消息死信
// for (int i = 0; i < 20; i++) {
// rabbitTemplate.convertAndSend("test_exchange_dlx","test.dlx.haha","我是一条消息,我会死吗?");
// }
//3. 测试消息拒收
rabbitTemplate.convertAndSend("test_exchange_dlx","test.dlx.haha","我是一条消息,我会死吗?");
}
@Component
public class DlxListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//1.接收转换消息
System.out.println(new String(message.getBody()));
//2. 处理业务逻辑
System.out.println("处理业务逻辑...");
int i = 3/0;//出现错误
//3. 手动签收
channel.basicAck(deliveryTag,true);
} catch (Exception e) {
//e.printStackTrace();
System.out.println("出现异常,拒绝接受");
//4.拒绝签收,不重回队列 requeue=false
channel.basicNack(deliveryTag,true,false);
}
}
}
<!--
延迟队列:
1. 定义正常交换机(order_exchange)和队列(order_queue)
2. 定义死信交换机(order_exchange_dlx)和队列(order_queue_dlx)
3. 绑定,设置正常队列过期时间为30分钟
-->
<!-- 1. 定义正常交换机(order_exchange)和队列(order_queue)-->
<rabbit:queue id="order_queue" name="order_queue">
<!-- 3. 绑定,设置正常队列过期时间为30分钟-->
<rabbit:queue-arguments>
<entry key="x-dead-letter-exchange" value="order_exchange_dlx" />
<entry key="x-dead-letter-routing-key" value="dlx.order.cancel" />
<entry key="x-message-ttl" value="10000" value-type="java.lang.Integer" />
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:topic-exchange name="order_exchange">
<rabbit:bindings>
<rabbit:binding pattern="order.#" queue="order_queue"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
<!-- 2. 定义死信交换机(order_exchange_dlx)和队列(order_queue_dlx)-->
<rabbit:queue id="order_queue_dlx" name="order_queue_dlx"></rabbit:queue>
<rabbit:topic-exchange name="order_exchange_dlx">
<rabbit:bindings>
<rabbit:binding pattern="dlx.order.#" queue="order_queue_dlx"></rabbit:binding>
</rabbit:bindings>
</rabbit:topic-exchange>
@Test
public void testDelay() throws InterruptedException {
//1.发送订单消息。 将来是在订单系统中,下单成功后,发送消息
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
rabbitTemplate.convertAndSend("order_exchange","order.msg","订单信息:id=1,time=" + sdf.format(new Date()));
/*//2.打印倒计时10秒
for (int i = 10; i > 0 ; i--) {
System.out.println(i+"...");
Thread.sleep(1000);
}*/
}
@Component
public class OrderListener implements ChannelAwareMessageListener {
@Override
public void onMessage(Message message, Channel channel) throws Exception {
long deliveryTag = message.getMessageProperties().getDeliveryTag();
try {
//1.接收转换消息
System.out.println(new String(message.getBody()));
//2. 处理业务逻辑
System.out.println("处理业务逻辑...");
System.out.println("根据订单id查询其状态...");
System.out.println("判断状态是否为支付成功");
System.out.println("取消订单,回滚库存....");
//3. 手动签收
channel.basicAck(deliveryTag,true);
} catch (Exception e) {
//e.printStackTrace();
System.out.println("出现异常,拒绝接受");
//4.拒绝签收,不重回队列 requeue=false
channel.basicNack(deliveryTag,true,false);
}
}
}
<rabbit:listener ref="orderListener" queue-names="order_queue_dlx"> </rabbit:listener>
@Configuration
public class MqConfig {
@Autowired
private Environment env;
/**
* 正常交换机
* @return
*/
@Bean
public Exchange ttlExchange() {
return ExchangeBuilder.directExchange(env.getProperty("mq.order.exchange.ttl")).durable(true).build();
}
/**
* 死信交换机
* @return
*/
@Bean
public Exchange dlxExchange() {
return ExchangeBuilder.directExchange(env.getProperty("mq.order.exchange.dlx")).durable(true).build();
}
/**
* 死信队列
* @return
*/
@Bean
public Queue dlxQueue() {
return QueueBuilder.durable(env.getProperty("mq.order.queue.dlx")).build();
}
/**
* 正常队列
* @return
*/
@Bean
public Queue ttlQueue() {
return QueueBuilder
.durable(env.getProperty("mq.order.queue.ttl"))
//队列的过期时间,10秒过期
.withArgument("x-message-ttl", 10000)
//指定死信交换机
.withArgument("x-dead-letter-exchange", env.getProperty("mq.order.exchange.dlx"))
.withArgument("x-dead-letter-routing-key", env.getProperty("mq.order.routing.dlx"))
.build();
}
/**
* 正常交换机,队列绑定
* @param queue
* @param exchange
* @return
*/
@Bean
public Binding ttlBinding(@Qualifier("ttlQueue") Queue queue, @Qualifier("ttlExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(env.getProperty("mq.order.routing.ttl")).noargs();
}
/**
* 死信交换机,队列绑定
* @param queue
* @param exchange
* @return
*/
@Bean
public Binding dlxBinding(@Qualifier("dlxQueue") Queue queue, @Qualifier("dlxExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(env.getProperty("mq.order.routing.dlx")).noargs();
}
}
@Component
@RabbitListener(queues = "${mq.pay.queue.order}")
public class OrderPayStatusListener {
@Autowired
private ObjectMapper objectMapper;
@Autowired
private IOrderService orderService;
@RabbitHandler
public void handlerData(String msg) {
//反序列化消息数据
Map<String, String> map = null;
try {
map = objectMapper.readValue(msg, Map.class);
} catch (IOException e) {
e.printStackTrace();
}
//更新订单状态
if (map != null) {
if (map.get("trade_status").equals("TRADE_SUCCESS")) {
orderService.updatePayStatus(map.get("out_trade_no"), map.get("trade_no"));
} else {
//删除订单,支付失败,回滚库存(作业)
}
}
}
}
@Component
@RabbitListener(queues = "${mq.order.queue.dlx}")
public class OrderLazyStatusListener {
@Autowired
private IOrderService orderService;
@RabbitHandler
public void handlerData(String msg) {
if (StringUtils.isNotEmpty(msg)) {
Long id = Long.parseLong(msg);
Order order = orderService.getById(id);
order.setOrderStatus("3");
orderService.updateById(order);
//回滚库存(作业)
}
}
}
rabbitTemplate.convertAndSend(env.getProperty("mq.order.exchange.ttl"), env.getProperty("mq.order.routing.ttl"), order.getId().toString());