Topics通配符模式说明:
Topic类型与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符!因此二者很相似
Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert
通配符规则:
#:匹配一个或多个词
*:匹配不多不少恰好1个词
举例:
item.#:能够匹配item.insert.abc 或者 item.insert
item.*:只能匹配item.insert
图解:
红色Queue:绑定的是usa.# ,因此凡是以 usa.开头的routing key 都会被匹配到
黄色Queue:绑定的是#.news ,因此凡是以 .news结尾的 routing key 都会被匹配
生产者
public class Producer {
public static void main(String[] args) throws IOException, TimeoutException {
//1. 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2. 设置参数
connectionFactory.setHost("localhost");//ip 默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setUsername("guest");//用户名 默认 guest
connectionFactory.setPassword("guest");//密码 默认值 guest
connectionFactory.setVirtualHost("/");//虚拟机 默认值
//3. 创建连接 Connection
Connection connection = connectionFactory.newConnection();
//4. 创建Channel
Channel channel = connection.createChannel();
// 创建交换机
String exchangeName = "test_topic";
/**
参数:
1. exchange:交换机名称
2. type:交换机类型
DIRECT("direct"),:定向
FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
TOPIC("topic"),通配符的方式
HEADERS("headers");参数匹配
3. durable:是否持久化
4. autoDelete:自动删除
5. internal:内部使用。 一般false
6. arguments:参数
*/
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC, true, false, false,null);
// 创建队列
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name,true,false,false,null);
// 绑定队列和交换机
/**
参数:
1. queue:队列名称
2. exchange:交换机名称
3. routingKey:路由键,绑定规则
如果交换机的类型为fanout ,routingKey设置为""
*/
channel.queueBind(queue1Name,exchangeName,"#.error");
channel.queueBind(queue1Name,exchangeName,"order.*");
channel.queueBind(queue2Name,exchangeName,"*.*");
//8. 发送消息order.error虽然queue1Name符合了两次,但是交换机只会把消息放到队列queue1Name中一次,也防止了重复
String body = "日志信息:张三调用了findAll方法...日志级别:info...";
channel.basicPublish(exchangeName,"order.error",null,body.getBytes());
//9. 释放资源
channel.close();
connection.close();
}
}
注意:多个消费者,每个消费者可能绑定的队列都不同,而且,不同队列与交换机之间绑定的路由规则也不同。我们要注意,此处我们只举例出一个消费者。
消费者
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2. 设置参数
connectionFactory.setHost("localhost");//ip 默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setUsername("guest");//用户名 默认 guest
connectionFactory.setPassword("guest");//密码 默认值 guest
connectionFactory.setVirtualHost("/");//虚拟机 默认值
//3. 创建连接 Connection
Connection connection = connectionFactory.newConnection();
//4. 创建Channel
Channel channel = connection.createChannel();
//5. 接收消息
String queue1Name = "test_topic_queue1";
String queue2Name = "test_topic_queue2";
Consumer consumer = new DefaultConsumer(channel){
/**
回调方法,当收到消息后,会自动执行该方法
1. consumerTag:标识
2. envelope:获取一些信息,交换机,路由key...
3. properties:配置信息
4. body:数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
System.out.println("将日志信息打印到控制台.....");
}
};
//参数:1. queue:队列名称 2. autoAck:是否自动确认 3. callback:回调对象
channel.basicConsume(queue1Name,true, consumer);
}
}
总结:
Topic主题模式可以实现 Publish/Subscribe发布与订阅模式 和 Routing路由模式 的功能;只是Topic在配置routing key 的时候可以使用通配符,显得更加灵活。