RabbitMQ使用场景

笔记

SpringBoot整合RabbitMQ

 

fanout模式
1.创建springboot项目添加依赖
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.4.4</version>
    <relativePath/>
</parent>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

 

2.配置RabbitMQ连接

server.port=8081

spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672


3.添加RabbitMQ配置类(方式1:在发送消息端配置)

@Configuration
public class RabbitMQConfig {


    // 1.声明fanout模式的交换机
    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("fanout_order_exchange",true,false);
    }


    // 2.声明队列 sms,fanout,queue email,fanout,queue,phone,fanout,queue
    @Bean
    public Queue phoneQueue1(){
        return new Queue("phone.fanout.queue",true);
    }
    @Bean
    public Queue smsQueue1(){
        return new Queue("sms.fanout.queue",true);
    }
    @Bean
    public Queue emailQueue1(){
        return new Queue("email.fanout.queue",true);
    }


    // 3.完成绑定关系(队列和交换机完成绑定关系)
    @Bean
    public Binding phoneBinding1(){
        return BindingBuilder.bind(phoneQueue()).to(fanoutExchange());
    }
    @Bean
    public Binding smsBinding1(){
        return BindingBuilder.bind(smsQueue()).to(fanoutExchange());
    }
    @Bean
    public Binding emailBinding1(){
        return BindingBuilder.bind(emailQueue()).to(fanoutExchange());
    }
}

 

4.编写service类发送消息

@Service
public class OrderService {


    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 模拟用户下单
     * @param userId
     * @param productId
     * @param num
     */
    public void makeOrder_fanoutExchange(String userId,String productId,int num){
        // 1.根据商品id查询库存是否充足

        // 2.保存订单
        String orderId = UUID.randomUUID().toString();
        System.out.println("订单生产成功:" + orderId);
        // 3.通过MQ来完成消息
        // 参数1:交换机  参数2:路由key/queue队列名称  参数3:消息内容8
//        String exchangeName = "fanout_order_exchange";
        String exchangeName = "fanout_order_exchange";
        String routingKey = "";
        rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
    }
}

 

5.测试类

@Autowired
private OrderService orderService;

@Test
void makeOrder_fanoutExchange1() {
    orderService.makeOrder_fanoutExchange("1","001",10);
}

 

6.配置消息接收方(导入依赖)

server.port=8082

spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=/
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672

 

7.接收方监听队列,处理消息(每个类单独配置,单独绑定队列)

@Service
@RabbitListener(queues = {"email.fanout.queue"})
public class EmailConsumer {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("Email_fanout->接收到了订单信息:" + msg);
    }
}


@Service
@RabbitListener(queues = {"phone.fanout.queue"})
public class PhoneConsumer {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("Phone_fanout->接收到了订单信息:" + msg);
    }
}


@Service
@RabbitListener(queues = {"sms.fanout.queue"})
public class SMSConsumer {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("SMS_fanout->接收到了订单信息:" + msg);
    }
}

 

8.测试接收消息

1.消息发送方测试类启动

2.开启消息接收方主类
SpringbootOrderRabbitmqConsumerApplication

 

9.效果展示

 

 

 

 

 

 

切换direct模式
1.配置类
@Configuration
public class RabbitMQConfig {

/* 修改为direct路由模式 */
@Bean
public DirectExchange directExchange(){
    return new DirectExchange("direct_order_exchange",true,false);
}

// 2.声明队列 sms,fanout,queue email,fanout,queue,phone,fanout,queue
@Bean
public Queue phoneQueue(){
    return new Queue("phone.direct.queue",true);
}
@Bean
public Queue smsQueue(){
    return new Queue("sms.direct.queue",true);
}
@Bean
public Queue emailQueue(){
    return new Queue("email.direct.queue",true);
}



// 3.完成绑定关系(队列和交换机完成绑定关系)
@Bean
public Binding phoneBinding(){
    return BindingBuilder.bind(phoneQueue()).to(directExchange()).with("phone");
}
@Bean
public Binding smsBinding(){
    return BindingBuilder.bind(smsQueue()).to(directExchange()).with("sms");
}
@Bean
public Binding smsBinding2(){
    return BindingBuilder.bind(smsQueue()).to(directExchange()).with("phone");
}
@Bean
public Binding emailBinding(){
    return BindingBuilder.bind(emailQueue()).to(directExchange()).with("email");

}

 

2.编写service类

@Service
public class OrderService {

public void makeOrder_directExchange(String userId,String productId,int num){
        // 1.根据商品id查询库存是否充足


        // 2.保存订单
        String orderId = UUID.randomUUID().toString();
        System.out.println("订单生产成功:" + orderId);
        // 3.通过MQ来完成消息
        // 参数1:交换机  参数2:路由key/queue队列名称  参数3:消息内容8
//        String exchangeName = "fanout_order_exchange";
        String exchangeName = "direct_order_exchange";
        String routingKey = "phone";
        rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
    }
}

 

3.测试类发送消息

@Test
void makeOrder_directExchange1() {
    orderService.makeOrder_directExchange("2","007",11);
}

 

4.接收方监听队列,处理消息(每个类单独配置,单独绑定队列)

@Service
@RabbitListener(queues = {"email.direct.queue"})
public class EmailConsumer1 {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("Email_direct->接收到了订单信息:" + msg);
    }
}

@Service
@RabbitListener(queues = {"phone.direct.queue"})
public class PhoneConsumer1 {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("Phone_direct->接收到了订单信息:" + msg);
    }
}


@Service
@RabbitListener(queues = {"sms.direct.queue"})
public class SMSConsumer1 {
    @RabbitHandler
    public void receiveMessage(String msg){
        System.out.println("SMS_direct->接收到了订单信息:" + msg);
    }
}

 

5.测试接收消息

1.消息发送方测试类启动


2.开启消息接收方主类
SpringbootOrderRabbitmqConsumerApplication

 

6.效果展示

 

 

 

 

 

 

切换topic模式
1.配置路由与队列绑定(绑定的另一种方式,在消息接收端)
/**
* 绑定路由与队列方式2
*/
@Component
@RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "topic_com_queue",durable = "true",autoDelete = "false"),
        exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC),    //默认是direct模式
        key = "com.#"
))
public class ComConsumer {
    @RabbitHandler
    public void receiveMessage(String message){
        System.out.println("com_topic->接收到了订单信息:" + message);
    }
}


@Component
@RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "topic_order_queue",durable = "true",autoDelete = "false"),
        exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC),
        key = "*.order.*"
))
public class OrderConsumer {
    @RabbitHandler
    public void receiveMessage(String message){
        System.out.println("order_topic->接收到了订单信息:" + message);
    }
}


@Component
@RabbitListener(bindings = @QueueBinding(
        value = @Queue(value = "topic_user_queue",durable = "true",autoDelete = "false"),
        exchange = @Exchange(value = "topic_order_exchange",type = ExchangeTypes.TOPIC),
        key = "#.user.#"
))
public class UserConsumer {
    @RabbitHandler
    public void receiveMessage(String message){
        System.out.println("user_topic->接收到了订单信息:" + message);
    }
}

 

2.开启消息接收端主类

SpringbootOrderRabbitmqConsumerApplication

 

3.编写service类

public void makeOrder_topicExchange(String userId,String productId,int num){
        // 1.根据商品id查询库存是否充足
        // 2.保存订单
        String orderId = UUID.randomUUID().toString();
        System.out.println("订单生产成功:" + orderId);
        // 3.通过MQ来完成消息
        // 参数1:交换机  参数2:路由key/queue队列名称  参数3:消息内容8
//        String exchangeName = "fanout_order_exchange";
        String exchangeName = "topic_order_exchange";
        // com.# *.order.* #.user.#
        String routingKey = "com.order.user";
        rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
        rabbitTemplate.convertAndSend(exchangeName,"com.order1.user",orderId);
    }

 

4.测试类测试

@Test
void makeOrder_topicExchange(){
    orderService.makeOrder_topicExchange("2","007",20);
}

 

 

RabbitMQ进阶

 

 

1.过期时间TTL

 

过期时间TTL表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取,过了之后消息将自动被删除,RabbitMQ可以对消息和队列设置TTL.目前有两种方法可以设置

 

 

第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间
1.配置TTL过期时间
/**
* 设置TTL过期时间消息队列
*/
@Configuration
public class TTLRabbitMQConfig {

    // 1.声明交换机
    @Bean
    public DirectExchange ttlDirectExchange(){
        return new DirectExchange("ttl_direct_exchange",true,false);
    }

    // 2.声明队列
    @Bean
    public Queue TTLDirectQueue(){
        Map<String,Object> args = new HashMap<>();
        args.put("x-message-ttl",10000);
        return new Queue("ttl.direct.queue",true,false,false,args);
    }

    // 3.完成绑定关系(队列和交换机完成绑定关系)
    @Bean
    public Binding TTLDirectBinding(){
        return BindingBuilder.bind(TTLDirectQueue()).to(ttlDirectExchange()).with("ttl");
    }
}

 

2.service发送消息

/**
* 给队列设置过期时间
* @param userId
* @param productId
* @param num
*/
public void makeOrder_TTL(String userId,String productId,int num){
    // 1.根据商品id查询库存是否充足


    // 2.保存订单
    String orderId = UUID.randomUUID().toString();
    System.out.println("订单生产成功:" + orderId);
    // 3.通过MQ来完成消息
    // 参数1:交换机  参数2:路由key/queue队列名称  参数3:消息内容8
    String exchangeName = "ttl_direct_exchange";
    String routingKey = "ttl";
    rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId);
}

 

3.效果:

 

 

 

第二种方法是对消息进行单独设置,每条消息TTL可以不同
 
1.配置消息队列绑定交换机
/**
* 设置TTL过期时间消息队列
*/
@Configuration
public class TTLRabbitMQConfig {

    // 1.声明fanout模式的交换机
    @Bean
    public DirectExchange ttlDirectExchange(){
        return new DirectExchange("ttl_direct_exchange",true,false);
    }

    @Bean
    public Queue TTLMessageQueue(){
        return new Queue("ttl.message.direct.queue",true);
    }

    @Bean
    public Binding TTLMsgDirectBinding(){
        return BindingBuilder.bind(TTLMessageQueue()).to(ttlDirectExchange()).with("ttlMessage");
    }
}

 

2.service发送消息

/**
     * 单独给消息设置过期时间
     * @param userId
     * @param productId
     * @param num
     */
    public void makeOrder_TTLMessage(String userId,String productId,int num){
        // 1.根据商品id查询库存是否充足
        // 2.保存订单
        String orderId = UUID.randomUUID().toString();
        System.out.println("订单生产成功:" + orderId);
        // 3.通过MQ来完成消息
        // 参数1:交换机  参数2:路由key/queue队列名称  参数3:消息内容8
        String exchangeName = "ttl_direct_exchange";
        String routingKey = "ttlMessage";

        MessagePostProcessor messagePostProcessor = new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setExpiration("10000");
                message.getMessageProperties().setContentEncoding("UTF-8");
                return message;
            }
        };
        
        // 重载方法
        rabbitTemplate.convertAndSend(exchangeName,routingKey,orderId,messagePostProcessor);
    }

 

注:
  两种方法同时使用时,消息的过期时间以两者之间TTL较小的那个数值为准,消息在队列的生存时间一旦超过设置的TTL值,就称为dead message被投递到死信队列,消费者将无法再收到该信息
 
 
死信队列(DLX)   
>>接盘侠<<
当消息在一个队列中变成死信之后,它能被重新发送到另一个交换机中,这个交换机就是DLX,绑定DLX的队列就称之为死信队列,消息变成死信,可能原因有:
  • 消息被拒绝
  • 消息过期
  • 队列达到最大长度
 
1.配置死信交换机和死信队列
 
/**
* 配置信息交换机和队列
*/
@Configuration
public class DeadRabbitMQConfig {

    // 1.声明交换机
    @Bean
    public DirectExchange deadDirectExchange(){
        return new DirectExchange("dead_direct_exchange",true,false);
    }

    // 2.声明队列
    @Bean
    public Queue DeadQueue(){
        return new Queue("dead.direct.queue",true);
    }

    // 3.完成绑定关系(队列和交换机完成绑定关系)
    @Bean
    public Binding DeadDirectBinding(){
        return BindingBuilder.bind(DeadQueue()).to(deadDirectExchange()).with("dead");
    }
}

 

2.消息队列关联死信队列

@Bean
    public Queue TTLDirectQueue(){
        /*
        * 这里修改过参数重新启动会报错,因为队列不会覆盖设置的属性值,
        * 所以需要重新定义一个新的队列实现(开发中禁止删除已有队列[丢失信息])
        * */
        Map<String,Object> args = new HashMap<>();
        // 设置过期时间
        args.put("x-message-ttl",10000);
        // 设置队列消息的长度 如果产生的消息大于5条,那么就会往死信队列转移
//        args.put("x-max-length","5");
        // 设置死信交换机
        args.put("x-dead-letter-exchange","dead_direct_exchange");
        // 设置死信routerKey-->fanout模式不需要配置
        args.put("x-dead-letter-routing-key","dead");


        return new Queue("ttl.direct.queue",true,false,false,args);
    }

 

3.启动ttl测试类发送信息

@Test
void makeOrder_TTL(){
    orderService.makeOrder_TTL("TTL","A001",10);
}

 

4.测试结果

 

posted @ 2021-04-27 19:17  G-G  阅读(79)  评论(0)    收藏  举报