完整架构: 生产者 - 信道 - (broker : 交换机 - 队列) - 信道 - 消费者
通过交换机来绑定队列可以实现多种消息传递到消费者的方式:
-
无名Exchange:写routingkey,exchange为null,即使用默认的交换机,所以的消费者通过竞争的方式可以获取全部消息,但是消息只可以获取一次,即一条消息只可以被一个消费者消费
-
fanout(扇出)模式:不用填写routingkey,绑定同一交换机的队列都可以接收全部消息,一条消息可以被所有绑定到这个交换机的队列的消费者消费
消费者1:
public class ReceiveLogs01 { public static final String EXCHANGE_NAME = "logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); // 声明交换机 channel.exchangeDeclare(EXCHANGE_NAME,"fanout"); /* 声明一个临时队列 生成一个临时队列,名字随机 当消费者断开连接之后,队列自动删除 */ String queue = channel.queueDeclare().getQueue(); channel.queueBind(queue,EXCHANGE_NAME,""); System.out.println("等待接收消息,把接收消息打印在屏幕上..."); channel.basicConsume(queue,true,((consumerTag, message) -> System.out.println("接收到的消息:"+new String(message.getBody(), StandardCharsets.UTF_8))), consumerTag -> {}); } }
消费者2:
public class ReceiveLogs02 { public static final String EXCHANGE_NAME = "logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); // 声明交换机 channel.exchangeDeclare(EXCHANGE_NAME,"fanout"); /* 声明一个临时队列 生成一个临时队列,名字随机 当消费者断开连接之后,队列自动删除 */ String queue = channel.queueDeclare().getQueue(); channel.queueBind(queue,EXCHANGE_NAME,""); System.out.println("等待接收消息,把接收消息打印在屏幕上..."); channel.basicConsume(queue,true,((consumerTag, message) -> System.out.println("接收到的消息:"+new String(message.getBody(), StandardCharsets.UTF_8))), consumerTag -> {}); } }
生产者:
public class EmitLog { public static final String EXCHANGE_NAME = "logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, "fanout"); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ String message = scanner.next(); channel.basicPublish(EXCHANGE_NAME,"", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes(StandardCharsets.UTF_8)); } } }
-
direct(直连)模式:根据routingkey来指定要发送到的队列,绑定到同一个交换机的队列绑定各自的routingkey,只有满足routingkey才能接收消息,消息只被消费一次,如果使用同一个routingkey就类似于扇出模式.
消费者1:
public class ReceiveLogsDirect01 { public static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); channel.queueDeclare("console",false,false,false,null); channel.queueBind("console",EXCHANGE_NAME,"info"); channel.queueBind("console",EXCHANGE_NAME,"warning"); channel.basicConsume("console",true,((consumerTag, message) -> System.out.println("接收到的消息:"+new String(message.getBody(), StandardCharsets.UTF_8))), consumerTag -> {}); } }
消费者2:
public class ReceiveLogsDirect02 { public static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); channel.queueDeclare("disk",false,false,false,null); channel.queueBind("disk",EXCHANGE_NAME,"error"); channel.basicConsume("disk",true,((consumerTag, message) -> System.out.println("接收到的消息:"+new String(message.getBody(), StandardCharsets.UTF_8))), consumerTag -> {}); } }
生产者:
public class DirectLogs { public static final String EXCHANGE_NAME = "direct_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.DIRECT); Scanner scanner = new Scanner(System.in); while (scanner.hasNext()){ String message = scanner.next(); channel.basicPublish(EXCHANGE_NAME,"info", MessageProperties.PERSISTENT_TEXT_PLAIN,message.getBytes(StandardCharsets.UTF_8)); } } }
-
topic(主题)模式:主题模式主要是对routingkey做了一个正则的判断,*表示一个单词,#表示零个或多个单词,只要正则正确就可以获取到消息,消息可以被不同消费者消费.
消费者:
public class ReceiveLogsTopic01 { public static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); channel.queueDeclare("Q1",false,false,false,null); channel.queueBind("Q1",EXCHANGE_NAME,"*.orange.*"); channel.basicConsume("Q1",true,(consumerTag, message) -> System.out.println("收到的信息:"+new String(message.getBody(), StandardCharsets.UTF_8)+"绑定键为:"+message.getEnvelope().getRoutingKey()),consumerTag -> {}); } }
public class ReceiveLogsTopic02 { public static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); channel.queueDeclare("Q2",false,false,false,null); channel.queueBind("Q2",EXCHANGE_NAME,"*.*.rabbit"); channel.queueBind("Q2",EXCHANGE_NAME,"lazy.#"); channel.basicConsume("Q2",true,(consumerTag, message) -> System.out.println("收到的信息:"+new String(message.getBody(), StandardCharsets.UTF_8)+"绑定键为:"+message.getEnvelope().getRoutingKey()),consumerTag -> {}); } }
生产者:
public class EmitLogTopic { public static final String EXCHANGE_NAME = "topic_logs"; public static void main(String[] args) throws IOException, TimeoutException { Channel channel = RabbitMqUtils.getChannel(); channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.TOPIC); Map<String,String> bindingKeyMap = new HashMap<>(); bindingKeyMap.put("quick.orange.rabbit","被队列Q1Q2接收到"); bindingKeyMap.put("lazy.orange.elephant","被队列Q1Q2接收到"); bindingKeyMap.put("quick.orange.fox","被队列Q1接收到"); bindingKeyMap.put("lazy.brown,fox","被队列Q2接收到"); bindingKeyMap.put("lazy.pink.rabbit","虽然满足两个绑定到Q2但是只接收一次"); bindingKeyMap.put("quick.brown.fox","不匹配任何绑定"); bindingKeyMap.put("quick.orange.male.rabbit","四个单词不匹配"); bindingKeyMap.put("lazy.orange.male.rabbit","四个单词但是匹配Q2接收"); for (Map.Entry<String, String> bindingKeyEntry : bindingKeyMap.entrySet()) { channel.basicPublish(EXCHANGE_NAME,bindingKeyEntry.getKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,bindingKeyEntry.getValue().getBytes(StandardCharsets.UTF_8)); System.out.println("生产者发出消息: "+bindingKeyEntry.getValue()); } } }