原生Java客户端与RabbitMQ通信
1.Direct
Maven依赖:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.0.0</version>
</dependency>
DirectProducer:direct类型交换器的生产者
package exchange.direct;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
*/
public class DirectProducer {
public final static String EXCHANGE_NAME = "direct_logs";
public static void main(String[] args) throws Exception {
//创建连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
Connection connection = connectionFactory.newConnection();
//创建信道
Channel channel = connection.createChannel();
//创建交换器
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//日志消息级别,作为路由键使用
String[] serverities = {"error", "info", "warning"};
for (int i = 0; i < 9; i++) {
String severity = serverities[i % 3];
String msg = "Hellol,RabbitMq" + (i + 1);
//发布消息
channel.basicPublish(EXCHANGE_NAME, severity, null, msg.getBytes());
}
channel.close();
connection.close();
}
}
NormalConsumer:普通的消费者
package exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
*/
public class NormalConsumer {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
//打开连接和创建信道,与发送端一样
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(DirectProducer.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
//声明一个队列
String queueName = "focuserror";
channel.queueDeclare(queueName, false, false,
false, null);
//将队列和交换器通过路由键绑定,表示只关注info级别的消息
String routeKey = "info";
channel.queueBind(queueName, DirectProducer.EXCHANGE_NAME, routeKey);
System.out.println("waiting for message........");
//声明一个消费者
Consumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
String message = new String(body, "UTF-8");
System.out.println("Received[" + envelope.getRoutingKey()
+ "]" + message);
}
};
channel.basicConsume(queueName, true, consumer);
}
}
MulitBindConsumer:队列绑定到交换器上时,是允许绑定多个路由键的,也就是多重绑定
package exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
*/
public class QueueMulitBindExchange {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(DirectProducer.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String queueName = channel.queueDeclare().getQueue();
//队列绑定多个路由键
String[] severities = {"error", "info", "warning"};
for (String serverity : severities) {
channel.queueBind(queueName, DirectProducer.EXCHANGE_NAME, serverity);
}
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties
properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" Received "
+ envelope.getRoutingKey() + ":'" + message
+ "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
MulitChannelConsumer:一个连接下允许有多个信道
package exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
*/
public class MulitChannelConsumer {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
Connection connection = factory.newConnection();
//一个连接多个信道
for(int i = 0; i < 3; i++){
Thread worker = new Thread(new ConsumerWorker(connection));
worker.start();
}
}
private static class ConsumerWorker implements Runnable {
final Connection connection;
public ConsumerWorker(Connection connection) {
this.connection = connection;
}
@Override
public void run() {
try {
Channel channel = connection.createChannel();
channel.exchangeDeclare(DirectProducer.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
String queueName = channel.queueDeclare().getQueue();
//消费者名字,打印输出用
final String consumerName
= Thread.currentThread().getName() + "-all";
//所有日志严重性级别
String[] severities={"error","info","warning"};
for (String severity : severities) {
//关注所有级别的日志(多重绑定)
channel.queueBind(queueName,
DirectProducer.EXCHANGE_NAME, severity);
}
System.out.println("["+consumerName+"] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties
properties,
byte[] body)
throws IOException {
String message =
new String(body, "UTF-8");
System.out.println(consumerName
+" Received " + envelope.getRoutingKey()
+ ":'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
MulitConsumerOneQueue:一个队列多个消费者,则会表现出消息在消费者之间的轮询发送。
package exchange.direct;
import com.rabbitmq.client.*;
import java.io.IOException;
/**
*/
public class MulitConsumerOneQueue {
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
Connection connection = factory.newConnection();
String queueName = "focusAll";
for (int i = 0; i < 3; i++) {
//一个连接多个信道,多个信道共享同一个队列
Thread worker = new Thread(new ConsumerWorker(connection, queueName));
worker.start();
}
}
private static class ConsumerWorker implements Runnable {
final Connection connection;
final String queueName;
public ConsumerWorker(Connection connection, String queueName) {
this.connection = connection;
this.queueName = queueName;
}
@Override
public void run() {
try {
Channel channel = connection.createChannel();
channel.exchangeDeclare(DirectProducer.EXCHANGE_NAME, BuiltinExchangeType.DIRECT);
channel.queueDeclare(queueName, false, false, false, null);
final String consumerName
= Thread.currentThread().getName();
//所有日志严重性级别
String[] severities={"error","info","warning"};
for (String severity : severities) {
//关注所有级别的日志(多重绑定)
channel.queueBind(queueName, DirectProducer.EXCHANGE_NAME, severity);
}
System.out.println(" ["+consumerName+"] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties
properties,
byte[] body)
throws IOException {
String message =
new String(body, "UTF-8");
System.out.println(consumerName
+" Received " + envelope.getRoutingKey()
+ ":'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
2.Fanout
消息广播到绑定的队列
- 生产者
package exchange.fanout;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
/**
*/
public class FanoutProducer {
public final static String EXCHANGE_NAME = "fanout_logs";
public static void main(String[] args) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//所有日志严重性级别
String[] severities = {"error", "info", "warning"};
for (int i = 0; i < 3; i++) {
String severity = severities[i % 3];
// 发送的消息
String message = "Hello World_"+(i+1);
channel.basicPublish(EXCHANGE_NAME, severity, null, message.getBytes());
System.out.println(" [x] Sent '" + severity +"':'"
+ message + "'");
}
// 关闭频道和连接
channel.close();
connection.close();
}
}
- 消费者1
package exchange.fanout;
import com.rabbitmq.client.*;
import javax.swing.event.ChangeListener;
import java.io.IOException;
/**
*/
public class Consumer1 {
public static void main(String[] args) throws Exception{
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(FanoutProducer.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
//声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
//所有日志严重性级别
String[] severities={"error","info","warning"};
for (String severity : severities) {
//关注所有级别的日志(多重绑定)
channel.queueBind(queueName, FanoutProducer.EXCHANGE_NAME, severity);
}
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope,
AMQP.BasicProperties properties, byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" Received " + envelope.getRoutingKey() + "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
- 消费者2
package exchange.fanout;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* @Author: Rab
* @Date: 2020-04-15 16:29
* @Description:
*/
public class Consumer2 {
public static void main(String[] argv) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(FanoutProducer.EXCHANGE_NAME,
BuiltinExchangeType.FANOUT);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
//只关注error级别的日志,然后记录到文件中去
String severity = "test";
channel.queueBind(queueName, FanoutProducer.EXCHANGE_NAME,
severity);
System.out.println(" [*] Waiting for messages......");
// 创建队列消费者
final Consumer consumerB = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
//记录日志到文件:
System.out.println("Received [" + envelope.getRoutingKey()
+ "] " + message);
}
};
channel.basicConsume(queueName, true, consumerB);
}
}
通过测试表明,不管我们如何调整生产者和消费者的路由键,都对消息的接受没有影响。
3.Topic
通过使用“”和“#”,使来自不同源头的消息到达同一个队列,”.”将路由键分为了几个标识符,“”匹配1个,“#”匹配一个或多个。例如日志处理:
假设有交换器log-exchange,
日志级别有error,info,warning,
应用模块有user,order,email,
服务器有 A、B、C、D
路由键的规则为 日志级别+“.”+应用模块名+“.”+服务器,如:info.email.A。
- 1、要关注A服务器发送的所有应用错误的消息,怎么做?
声明队列名称为“a-app-error-queue”并绑定到交换器上:channel. queueBind (‘a-app-error-queue’,’logs-change’,’error.*.A’) - 2、关注B服务器发送的的所有日志,怎么办?
声明队列名称为“b-all-queue”并绑定到交换器上:channel. queueBind (b-all-queue’,’logs-change’,’ #.B’)或channel. queueBind (b-all-queue’,’logs-change’,’ ..B’) - 3、关注所有服务器发送的email的所有日志,怎么办?
声明队列名称为“email-all-queue”并绑定到交换器上:channel. queueBind (email -all-queue’,’logs-change’,’ .email.’) - 4、想要接收所有日志:channel->queue_bind(‘all-log’,’logs-change’,’#’)
TopicProducer
package exchange.topic;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
*
*/
public class TopicProducer {
public final static String EXCHANGE_NAME = "topic_logs";
public static void main(String[] args)
throws IOException, TimeoutException {
/**
* 创建连接连接到RabbitMQ
*/
ConnectionFactory factory = new ConnectionFactory();
// 设置MabbitMQ所在主机ip或者主机名
factory.setHost("127.0.0.1");
// 创建一个连接
Connection connection = factory.newConnection();
// 创建一个信道
Channel channel = connection.createChannel();
// 指定转发
channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
/*日志消息,路由键最终格式类似于:info.order.B*/
String[] severities = {"error", "info", "warning"};
for (int i = 0; i < 3; i++) {
String[] modules = {"user", "order", "email"};
for (int j = 0; j < 3; j++) {
String[] servers = {"A", "B", "C"};
for (int k = 0; k < 3; k++) {
// 发送的消息
String message = "Hello Topic_[" + i + "," + j + "," + k + "]";
String routeKey = severities[i % 3] + "." + modules[j % 3]
+ "." + servers[k % 3];
channel.basicPublish(EXCHANGE_NAME, routeKey, null, message.getBytes());
System.out.println(" [x] Sent '" + routeKey + ":'"
+ message + "'");
}
}
}
// 关闭频道和连接
channel.close();
connection.close();
}
}
订阅所有消息
package exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
*/
public class AllConsumer {
public static void main(String[] argv) throws IOException,
InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(TopicProducer.EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName,TopicProducer.EXCHANGE_NAME,
"#");
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" AllConsumer Received "
+ envelope.getRoutingKey()
+ "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
所有Email消息
package exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
*
*/
public class EmailAllConsumer {
public static void main(String[] argv) throws IOException,
InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(TopicProducer.EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, TopicProducer.EXCHANGE_NAME, "*.email.*");
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" AllConsumer Received "
+ envelope.getRoutingKey()
+ "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
所有错误日志消息
package exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
*/
public class ErrorAllConsumer {
public static void main(String[] argv) throws IOException,
InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(TopicProducer.EXCHANGE_NAME,
BuiltinExchangeType.TOPIC);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, TopicProducer.EXCHANGE_NAME,
"error.#");
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" AllConsumer Received "
+ envelope.getRoutingKey()
+ "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
A发出的所有错误消息
package exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class ServerAErrorConsumer {
public static void main(String[] argv) throws IOException,
InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(TopicProducer.EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, TopicProducer.EXCHANGE_NAME, "error.*.A");
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" AllConsumer Received "
+ envelope.getRoutingKey()
+ "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}
B发出的所有消息
package exchange.topic;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
*
*/
public class ServerBAllConsumer {
public static void main(String[] argv) throws IOException,
InterruptedException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
// 打开连接和创建频道,与发送端一样
Connection connection = factory.newConnection();
final Channel channel = connection.createChannel();
channel.exchangeDeclare(TopicProducer.EXCHANGE_NAME, BuiltinExchangeType.TOPIC);
// 声明一个随机队列
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, TopicProducer.EXCHANGE_NAME, "#.B");
System.out.println(" [*] Waiting for messages:");
// 创建队列消费者
final Consumer consumerA = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body)
throws IOException {
String message = new String(body, "UTF-8");
System.out.println(" AllConsumer Received "
+ envelope.getRoutingKey()
+ "':'" + message + "'");
}
};
channel.basicConsume(queueName, true, consumerA);
}
}