Topic类型与Direct相比,都是可以根据RoutingKey把消息路由到不同的队列。只不过Topic类型Exchange可以让队列在绑定Routing key 的时候使用通配符!
Routingkey 一般都是有一个或多个单词组成,多个单词之间以”.”分割,例如: item.insert
通配符规则:
#:匹配一个或多个词
*:匹配不多不少恰好1个词
举例:
item.#:能够匹配item.insert.abc 或者 item.insert
item.*:只能匹配item.insert
代码演示
消息生产者
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 ProducerTopics {
public static void main(String[] args) throws IOException, TimeoutException {
//创建连接工厂
ConnectionFactory factory =new ConnectionFactory();
//设置参数
factory.setUsername("wujian");
factory.setPassword("wujian");
factory.setVirtualHost("/itcast");
factory.setHost("127.0.0.1");
factory.setPort(5672);
//创建连接
Connection connection =factory.newConnection();
//创建通道
Channel channel =connection.createChannel();
//创建交换机
/** public DeclareOk exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal,Map<String, Object> arguments) throws IOException {
return this.exchangeDeclare(exchange, type.getType(), durable, autoDelete, arguments);
String exchange 交换机名称
BuiltinExchangeType type 交换机类型
DIRECT("direct"), 点对点交换机
FANOUT("fanout"), 广播形式的交换机
TOPIC("topic"), 通配符形式的交换机
HEADERS("headers"); 很少用不做学习
boolean durable 是否持久化
boolean autoDelete 是否自动删除
boolean internal 内部 一般设置为false
Map<String, Object> arguments 参数
}*/
channel.exchangeDeclare("topics_exchange", BuiltinExchangeType.TOPIC,true,false,false,null);
/** public com.rabbitmq.client.AMQP.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments)
queue 队列的名称
durable 是否持久化,当mq重启之后还在
exclusive 是否独占,只有一个消费者监听这个队列
当connection 关闭的时候删除这个队列
autoDelete 是否自动删除,没有消费者的时候删除
arguments 参数
}*/
//创建队列
channel.queueDeclare("topics1",true,false,false,null);
channel.queueDeclare("topics2",true,false,false,null);
//队列与交换机绑定
channel.queueBind("topics1","topics_exchange","order.#");
channel.queueBind("topics1","topics_exchange","pay.#");
channel.queueBind("topics2","topics_exchange","*.*");
//发送消息
/**public void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body) throws IOException {
exchange 交换机名称,简单模式下的交换机会默认使用 ""
routingKey 路由名称
props 配置信息
body 消息体
*/
//channel.basicPublish("topics_exchange","order.insert",null,"这是一个订单插入的消息".getBytes());
channel.basicPublish("topics_exchange","product.insert",null,"这是一个只有topics2才能收到的消息".getBytes());
channel.close();
connection.close();
}
}
消息消费者1
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class CunsumerTopics {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setVirtualHost("/itcast");
factory.setUsername("wujian");
factory.setPassword("wujian");
//创建连接
Connection connection =factory.newConnection();
//创建连接通道
Channel channel =connection.createChannel();
DefaultConsumer consumer = new DefaultConsumer(channel){
/****
* consumerTag 标识 编号
* envelope 获取一些信息例如交换机 key,路由
* properties 配置信息
* body 数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
// System.out.println("标识:" + consumerTag);
// System.out.println("一些信息" + envelope.getExchange());
// System.out.println("这个是路由,其实是队列名称" + envelope.getRoutingKey());
// System.out.println("消息序号" + envelope.getDeliveryTag());
// System.out.println("配置信息:" + properties);
System.out.println("消息" + new String(body));
System.out.println("topics1收到了哪些消息.....");
}
};
channel.basicConsume("topics1",consumer);
}
}
消息生产者2
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class CunsumerTopics1 {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setPort(5672);
factory.setVirtualHost("/itcast");
factory.setUsername("wujian");
factory.setPassword("wujian");
//创建连接
Connection connection =factory.newConnection();
//创建连接通道
Channel channel =connection.createChannel();
DefaultConsumer consumer = new DefaultConsumer(channel){
/****
* consumerTag 标识 编号
* envelope 获取一些信息例如交换机 key,路由
* properties 配置信息
* body 数据
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
System.out.println("标识:" + consumerTag);
System.out.println("一些信息" + envelope.getExchange());
System.out.println("这个是路由,其实是队列名称" + envelope.getRoutingKey());
System.out.println("消息序号" + envelope.getDeliveryTag());
System.out.println("配置信息:" + properties);
System.out.println("消息" + new String(body));
System.out.println("topics2收到了哪些消息.....");
}
};
channel.basicConsume("topics2",consumer);
}
}
演示结果
总结
Topic主题模式可以实现 Publish/Subscribe发布与订阅模式 和 Routing路由模式 的功能;只是Topic在配置routing key 的时候可以使用通配符,显得更加灵活
模式总结
RabbitMQ工作模式:
1、简单模式 HelloWorld
一个生产者、一个消费者,不需要设置交换机(使用默认的交换机)
2、工作队列模式 Work Queue
一个生产者、多个消费者(竞争关系),不需要设置交换机(使用默认的交换机)
3、发布订阅模式 Publish/subscribe
需要设置类型为fanout的交换机,并且交换机和队列进行绑定,当发送消息到交换机后,交换机会将消息发送到绑定的队列
4、路由模式 Routing
需要设置类型为direct的交换机,交换机和队列进行绑定,并且指定routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列
5、通配符模式 Topic
需要设置类型为topic的交换机,交换机和队列进行绑定,并且指定通配符方式的routing key,当发送消息到交换机后,交换机会根据routing key将消息发送到对应的队列