rabbitmq的4种交换机

RabbitMQ交换机类型

1、Direct exchange: 直连交换机,根据Routing Key(路由键)进行投递到不同队列。

路由键1
路由键2
Direct exchange
消息队列1
消息队列2

代码实现:

消息发送者,在pom.xml导入相关依赖
	<dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-amqpartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
     dependencies>

在application.yml自定义direct交换机的属性
# 应用名称
spring:
  application:
    name:
      001-rabbitmq-send
  rabbitmq:
    host: 192.168.126.124 #rabbitmq服务器地址
    port: 5672 #AMQP协议端口
    username: admin #账号
    password: admin #密码
    virtual-host: / #虚拟机
server:
  port:
    1001

#自定义消息队列的属性
custom:
  rabbitmq:
    # direct类型的消息的发送
    direct:
      queue-name: directQueue
      exchange-name: directExchange
      routing-key: directRoutingKey
读取application.yml自定义属性付给实体类对象
@Data
@Component
@ConfigurationProperties(prefix = "custom.rabbitmq.direct")
public class ExchangeProperties {
    private String queueName;
    private String exchangeName;
    private String routingKey;
}

声明Direct类型交换机、消息队列、绑定关系
@Configuration
public class RabbitMqConfiguration {
    @Autowired
    private ExchangeProperties exchangeProperties

    //声明Direct类型交换机、消息队列、绑定关系
    @Bean
    public DirectExchange directExchange(){
        //默认创建的交换机为持久化、非自动删除(自动删除没有监听的交换机,该交换机会被自动删除)的交换机
        return new DirectExchange(exchangeProperties.getExchangeName());
    }

    @Bean
    public Queue directQueue(){
        //默认创建的消息队列持久化、非自动删除、非排外(当前消息可以被任意消息消费,但是只能有一个消费者消费)
        return new Queue(exchangeProperties.getQueueName());
    }

    @Bean
    public Binding directBinding(Queue directQueue,DirectExchange directExchange){
        return BindingBuilder
                .bind(directQueue)
                .to(directExchange)
                .with(exchangeProperties.getRoutingKey());
    }

}
消息发送者发送消息
@Service
public class SendMsgImpl implements SendMsg {
    @Autowired
    private RabbitTemplate rabbitTemplate;

 
    @Autowired
    private ExchangeProperties exchangeProperties;


    @Override
    public void sendDirectMessage() throws JsonProcessingException {


        rabbitTemplate.convertAndSend(
                exchangeProperties.getExchangeName(),
                exchangeProperties.getRoutingKey(),
                "这是第2条测试消息"
        );
    }
}
消息接收者,application.yml
# 应用名称
spring:
  application:
    name:
      001-rabbitmq-receive
  rabbitmq:
    host: 192.168.126.124 #rabbitmq服务器地址
    port: 5672 #AMQP协议端口
    username: admin #账号
    password: admin #密码
    virtual-host: / #虚拟机
    listener:
      simple:
        #消息确认机制,manual表示手动确认,auto代表自动确认
        acknowledge-mode: manual
# 应用服务 WEB 访问端口
server:
  port:
    2001
消息接收者接收消息并手动确认消息
package com.wen.servive.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
import com.wen.servive.ReceiveMsg;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;

@Service
public class ReceiveMsgImpl implements ReceiveMsg {

    @RabbitListener(queues = "directQueue")
    public void receiveDirectMessage(Message msg, Channel channel) throws IOException {
        System.out.println(msg);
        //手动消费,注入一个参数Channel对象
        channel.basicAck(
                //根据消息标识,来手动消费消息
                msg.getMessageProperties().getDeliveryTag(),false);
    }
}

2、Fanout exchange
不使用路由键,使用广播模式,将消息传递到所有绑定Fanout exchang的消息队列,当消息队列未被消息消费者监听时,自动删除消息队列,所以消息队列的消息是非持久化。

binding
binding
Direct exchange
消息队列1
消息队列2
消息发送者,application.yml自定义fanout交换机的属性
#自定义消息队列的属性
custom:
  rabbitmq:
    # fanout类型的消息的发送
    fanout:
      queue-name: fanoutQueue
      exchange-name: fanoutExchange
读取application.yml自定义属性付给实体类对象
@Data
@Component
@ConfigurationProperties(prefix = "custom.rabbitmq.fanout")
public class FanoutProperties {

    private String queueName;
    private String exchangeName;
}
消息发送者发送消息
   @Override
    public void sendFanoutMessage() throws JsonProcessingException {
        rabbitTemplate.convertAndSend(
                //Fanout交换机没有路由键
                fanoutProperties.getExchangeName(), "","这是第3条测试消息");

    }

消息接收者接收消息服务
 - 声明fanout类型交换机、消息队列、绑定关系 
 - 接收消息
   @RabbitListener(bindings = {
            @QueueBinding(
                    //声明绑定关系中的消息队列,如果没有命名消息队列名称,是随机命名的名称
                    value = @Queue,
                    exchange = @Exchange(name="fanoutExchange",type = "fanout")
            )
    })
    public void receiveFanoutMessage(Message msg, Channel channel) throws IOException {
        System.out.println(msg);
        //手动消费,注入一个参数Channel对象
        channel.basicAck(
                //根据消息标识,来手动消费消息
                msg.getMessageProperties().getDeliveryTag(), false
        );
    }

3、Topic exchange:主题交换机,对路由键进行模式匹配后进行投递,符号#表示一个或多个词,.表示一个词。

例子:
路由键为routingKeyA aa,routingKeyB aa.bb,routingKeyC aa.bb.cc
Topic exchange的路由通配规则如下
aa.*  必须以aa开头的两个单词,只有routingKeyB符合
aa.# 必须以aa开头的零个或多个单词,routingKeyA routingKeyB routingKeyC符合
消息发送者,application.yml自定义Topic 交换机的属性
#自定义消息队列的属性
custom:
  rabbitmq:
      # topic类型的消息的发送
    topic:
      queue-name1: topicQueue1
      queue-name2: topicQueue2
      queue-name3: topicQueue3
      binding-key1: aa
      binding-key2: aa.*
      binding-key3: aa.#
      exchange-name: topicExchange
      routing-key1: aa
      routing-key2: aa.bb
      routing-key3: aa.bb.cc
读取application.yml自定义属性付给实体类对象
@Data
@Component
@ConfigurationProperties(prefix = "custom.rabbitmq.topic")
public class TopicProperties {
    private String queueName1;
    private String queueName2;
    private String queueName3;
    private String bindingKey1;
    private String bindingKey2;
    private String bindingKey3;
    private String exchangeName;
    private String routingKey1;
    private String routingKey2;
    private String routingKey3;
}

声明Topic类型交换机、消息队列、绑定关系
@Configuration
public class RabbitMqConfiguration {
   
    @Autowired
    private TopicProperties topicProperties;

    //声明 Topic类型交换机(1)、消息队列(3)、绑定关系(3)
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange(topicProperties.getExchangeName());
    }
    @Bean
    public Queue topicQuene1(){
        return new Queue(topicProperties.getQueueName1());
    }

    @Bean
    public Queue topicQuene2(){
        return new Queue(topicProperties.getQueueName2());
    }
    @Bean
    public Queue topicQuene3(){
        return new Queue(topicProperties.getQueueName3());
    }

    @Bean
    public Binding topicBinding1(){
        return BindingBuilder
                .bind(topicQuene1())
                .to(topicExchange())
                .with(topicProperties.getBindingKey1());
    }

    @Bean
    public Binding topicBinding2(){
        return BindingBuilder
                .bind(topicQuene2())
                .to(topicExchange())
                .with(topicProperties.getBindingKey2());
    }
    @Bean
    public Binding topicBinding3(){
        return BindingBuilder
                .bind(topicQuene3())
                .to(topicExchange())
                .with(topicProperties.getBindingKey3());
    }
}
消息发送者发送消息
 @Override
    public void sendTopicMessage() throws JsonProcessingException {
        rabbitTemplate.convertAndSend(
                topicProperties.getExchangeName(), topicProperties.getRoutingKey1(),"这是第4条测试消息");

        rabbitTemplate.convertAndSend(
                //Fanout交换机没有路由键
                topicProperties.getExchangeName(), topicProperties.getRoutingKey2(),"这是第5条测试消息");

        rabbitTemplate.convertAndSend(
                //Fanout交换机没有路由键
                topicProperties.getExchangeName(), topicProperties.getRoutingKey3(),"这是第6条测试消息");
    }

消息接收者接收消息
   @RabbitListener(queues = {"topicQueue1",
            "topicQueue2",
            "topicQueue3"
            })
    public void receiveTopicMessage(Message msg, Channel channel) throws IOException {
        System.out.println(msg);
        //手动消费,注入一个参数Channel对象
        channel.basicAck(
                //根据消息标识,来手动消费消息
                msg.getMessageProperties().getDeliveryTag(), false
        );
    }

4、Header exchange:头交换机,不处理路由键。而是根据发送的消息内容中的headers属性进行匹配。

死信队列:存放过期消息的队列,对应有死信交换机和死信消费者

消息发送者,application.yml自定义正常交换机和死信交换机的属性
#自定义消息队列的属性
custom:
  rabbitmq:
    #模拟死性队列的场景 ,direct类型的交换机
    model:
      queue-name: modelQuene
      exchange-name: modelExchange
      routing-key: modelRoutingKey
    #direct类型的交换机
    dead:
      queue-name: deadQuene
      exchange-name: deadExchange
      routing-key: deadRoutingKey

读取application.yml自定义属性付给实体类对象
@Data
@Component
@ConfigurationProperties(prefix = "custom.rabbitmq.model")
public class ModelProperties {
    private String queueName;
    private String exchangeName;
    private String routingKey;
}

@Data
@Component
@ConfigurationProperties(prefix = "custom.rabbitmq.dead")
public class DeadProperties {
    private String queueName;
    private String exchangeName;
    private String routingKey;
}
声明正常交换机和死信交换机、消息队列、绑定关系
@Configuration
public class RabbitMqConfiguration {
    @Autowired
    private ModelProperties modelProperties;

    @Autowired
    private DeadProperties deadProperties;
    
    //声明死性队列场景
    //向Model中发送消息,等待消息过期,会自动发送到死信交换机中,根据死信routingKey转发到死信队列中
    @Bean
    public DirectExchange modelExchange(){
        return new DirectExchange(modelProperties.getExchangeName());
    }
    @Bean
    public Queue modelQuene(){
        Map<String,Object> arguments = new HashMap<>();
        //指定消息过期的时间,30秒过期
        arguments.put("x-message-ttl",30*1000);
        //指定死信交换机
        arguments.put("x-dead-letter-exchange",deadProperties.getExchangeName());
        //指定死信routingKey
        arguments.put("x-dead-letter-routing-key",deadProperties.getRoutingKey());
        return new Queue(modelProperties.getQueueName(),true,false,false,arguments);
    }

    @Bean
    public Binding modelBinding(){
        return BindingBuilder
                .bind(modelQuene())
                .to(modelExchange())
                .with(modelProperties.getRoutingKey());
    }

    @Bean
    public DirectExchange deadExchange(){
        return new DirectExchange(deadProperties.getExchangeName());
    }
    @Bean
    public Queue deadQuene(){
        return new Queue(deadProperties.getQueueName());
    }
    @Bean
    public Binding deadBinding(){
        return BindingBuilder
                .bind(deadQuene())
                .to(deadExchange())
                .with(deadProperties.getRoutingKey());
    }
}
消息发送者发送消息到正常交换机
    @Override
    public void sendModelMessage() throws JsonProcessingException {
        rabbitTemplate.convertAndSend(
                modelProperties.getExchangeName(), modelProperties.getRoutingKey(),"这是第7条测试消息");
    }

死信消息接收者接收消息

@Service
public class ReceiveMsgImpl implements ReceiveMsg {
   
    //接收modelQueue的消息队列,测试死信队列,这里不能消费消息
   // @RabbitListener(queues = "modelQueue")
    public void receiveModelMessage(Message msg, Channel channel) throws IOException {
        System.out.println(msg);
        //手动消费,注入一个参数Channel对象
        channel.basicAck(
                //根据消息标识,来手动消费消息
                msg.getMessageProperties().getDeliveryTag(), false
        );
    }

    //  当modelQueue消息超时时,会被转发到死信队列中进行处理
    @RabbitListener(queues = "deadQuene")
    public void receiveDeadMessage(Message msg, Channel channel) throws IOException {
        System.out.println("receiveDeadMessage:"+msg);
        //手动消费,注入一个参数Channel对象
        channel.basicAck(
                //根据消息标识,来手动消费消息
                msg.getMessageProperties().getDeliveryTag(), false);
    }
}

你可能感兴趣的:(消息中间件,java-rabbitmq,rabbitmq,java)