概念:
-
队列与交换机的绑定,不能是任意绑定了,而是要指定一个 RoutingKey(路由key)
-
消息的发送方在向 Exchange 发送消息时,也必须指定消息的 RoutingKey
-
Exchange 不再把消息交给每一个绑定的队列,而是根据消息的 Routing Key 进行判断,只有队列的Routingkey 与消息的 Routing key 完全一致,才会接收到消息
-
P:生产者,向 Exchange 发送消息,发送消息时,会指定一个routing key
-
X:Exchange(交换机),接收生产者的消息,然后把消息递交给与 routing key 完全匹配的队列
-
C1:消费者,其所在队列指定了需要 routing key 为 error 的消息
-
C2:消费者,其所在队列指定了需要 routing key 为 info、error、warning 的消息
生产者 producer:
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 Producer_Routing {
public static void main(String[] args) throws IOException, TimeoutException {
/**
* 1、创建连接工厂
* 2、设置参数
* 3、创建连接 Connection
* 4、创建Channel
* 5、创建交换机
* 6、创建队列
* 7、绑定队列和交换机
* 8、发送消息
* 9、释放资源
*/
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置参数
factory.setHost("192.168.16.62"); // ip 默认值 localhost
factory.setPort(5672); // 端口 默认值 5672
factory.setVirtualHost("/"); //虚拟机 默认值 /
factory.setUsername("guest"); // 用户名 默认值 guest
factory.setPassword("guest"); // 密码 默认值 guest
// 3、创建连接 Connection
Connection connection = factory.newConnection();
// 4、创建Channel
Channel channel = connection.createChannel();
// 5、创建交换机
/*
exchangeDeclare(
String exchange, //交换机名称
BuiltinExchangeType type,
//交换机类型 4种:
DIRECT("direct"), //定向
FANOUT("fanout"), //扇形(广播),发送消息到每一个队列
TOPIC("topic"), //通配符方式
HEADERS("headers"); //参数匹配
boolean durable, //是否持久化
boolean autoDelete, //自动删除
boolean internal, //内部使用。一般false
Map<String, Object> arguments //参数
)
*/
String exchangeName = "test_direct";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT, true, false, false, null);
// 6、创建队列
/*
queueDeclare(
String queue, //队列名称
boolean durable, //是否持久化, 当mq重启后,还在
boolean exclusive, //是否独占,只能有一个消费者监听此队列;当Connection关闭时,是否删除队列
boolean autoDelete, // 是否自动删除。当没有Consumer时自动删除
Map<String, Object> arguments //参数信息,删除的信息
)
*/
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name, true, false, false, null);
// 7、绑定队列和交换机
/*
queueBind(
String queue, //队列名称
String exchange, //交换机名称
String routingKey,
//路由键,绑定规则,如果交换机的类型为 FANOUT ,routingKey 设置为 ""
Map<String, Object> arguments //
)
*/
// 队列 1 的绑定
channel.queueBind(queue1Name, exchangeName, "error");
// 队列 2 的绑定
channel.queueBind(queue2Name, exchangeName, "error");
channel.queueBind(queue2Name, exchangeName, "info");
channel.queueBind(queue2Name, exchangeName, "warning");
// 8、发送消息
/*
basicPublish(
String exchange, // 交换机名称。简单模式下使用默认交换机:""
String routingKey, // 路由名称
BasicProperties props, // 配置信息
byte[] body // 发送消息数据
)
*/
String body1 = "日志信息:findALl 日志级别:info";
String body2 = "日志信息:findALl 日志级别:error";
channel.basicPublish(exchangeName,"info",null,body1.getBytes());
channel.basicPublish(exchangeName,"error",null,body2.getBytes());
// 9、释放资源
channel.close();
connection.close();
}
}
消费者 consumer:
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 接收消息
*/
public class Consumer_Routing1 {
public static void main(String[] args) throws IOException, TimeoutException {
/**
* 1、创建连接工厂
* 2、设置参数
* 3、创建连接 Connection
* 4、创建Channel
* 5、创建队列
* 6、接收消息
*/
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置参数
// ip 默认值 localhost, 192.168.16.62 :启动MQ服务器的ip
factory.setHost("192.168.16.62");
factory.setPort(5672); // 端口 默认值 5672
factory.setVirtualHost("/"); //虚拟机 默认值 /
factory.setUsername("guest"); // 用户名 默认值 guest
factory.setPassword("guest"); // 密码 默认值 guest
// 3、创建连接 Connection
Connection connection = factory.newConnection();
// 4、创建Channel
Channel channel = connection.createChannel();
// 5、创建队列, 生产者已经创建,无需再声明
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
//6、接收消息
/*
basicConsume(
String queue, // 队列名称
boolean autoAck, // 是否自动确认
Consumer callback // 回调对象
)
*/
Consumer consumer = new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
handleDelivery(
String consumerTag, // 标识
Envelope envelope, // 获取一些信息,交换机,路由key
AMQP.BasicProperties properties, //配置信息
byte[] body) // 数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// System.out.println("consumerTag : "+consumerTag);
// System.out.println("envelope : "+envelope);
// System.out.println("properties : "+properties);
System.out.println("数据库:" + new String(body));
}
};
channel.basicConsume(queue1Name,true,consumer);
}
}
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
* 接收消息
*/
public class Consumer_Routing2 {
public static void main(String[] args) throws IOException, TimeoutException {
/**
* 1、创建连接工厂
* 2、设置参数
* 3、创建连接 Connection
* 4、创建Channel
* 5、创建队列
* 6、接收消息
*/
// 1、创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 2、设置参数
// ip 默认值 localhost, 192.168.16.62 :启动MQ服务器的ip
factory.setHost("192.168.16.62");
factory.setPort(5672); // 端口 默认值 5672
factory.setVirtualHost("/"); //虚拟机 默认值 /
factory.setUsername("guest"); // 用户名 默认值 guest
factory.setPassword("guest"); // 密码 默认值 guest
// 3、创建连接 Connection
Connection connection = factory.newConnection();
// 4、创建Channel
Channel channel = connection.createChannel();
// 5、创建队列, 生产者已经创建,无需再声明
String queue1Name = "test_direct_queue1";
String queue2Name = "test_direct_queue2";
//6、接收消息
/*
basicConsume(
String queue, // 队列名称
boolean autoAck, // 是否自动确认
Consumer callback // 回调对象
)
*/
Consumer consumer = new DefaultConsumer(channel){
/*
回调方法,当收到消息后,会自动执行该方法
handleDelivery(
String consumerTag, // 标识
Envelope envelope, // 获取一些信息,交换机,路由key
AMQP.BasicProperties properties, //配置信息
byte[] body) // 数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
// System.out.println("consumerTag : "+consumerTag);
// System.out.println("envelope : "+envelope);
// System.out.println("properties : "+properties);
System.out.println("控制台:" + new String(body));
}
};
channel.basicConsume(queue2Name,true,consumer);
}
}
结果:
小结:
Routing 模式要求队列在绑定交换机时要指定 routing key,消息会转发到符合 routing key 的队列。