Message queue 消息队列--RabbitMQ 【基础入门】

Message queue 消息队列--RabbitMQ 【基础入门】_第1张图片

一,Message queue介绍:

1.1使用消息队列的优点:

服务之间最常见的通信方式是直接调用彼此来通信,消息从一端发出后立即就可以达到另一端,称为即时消息通讯(同步通信) 消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端,称为延迟消息通讯(异步通信)

如下:如果我们不使用MQ的话由订单直接调用其他的方法就会有几个问题:

1.过度耦合:如果后面创建订单时,需要触发新的动作,那就得去改代码,在原有的创建订单函数末尾,再追加一行代码

2.缺少缓冲:如果创建订单时,会员系统恰好处于非常忙碌或者宕机的状态,那这时更新会员信息就会失败,我们需要一个地方,来暂时存放无法被消费的消息

Message queue 消息队列--RabbitMQ 【基础入门】_第2张图片

解决:需要一个消息中间件,来实现解耦和缓冲的功能.

Message queue 消息队列--RabbitMQ 【基础入门】_第3张图片

二,RabbitMQ介绍:

2.1什么是RabbitMQ?

RabbitMQ是一个功能强大的消息队列中间件,被广泛应用于分布式系统、微服务架构和异步任务处理等场景。它提供了丰富的特性和灵活的配置选项,能够满足各种不同的需求。同时也有其他的MQ,RabbitMQ只是消息队列的一种。

2.2RabbitMQ组成?
  1. 消息队列:消息队列是一种在应用程序之间进行异步通信的方式。发送方将消息发送到队列,接收方从队列中接收消息并进行处理。这种方式能够解耦发送方和接收方,提高系统的可靠性和可扩展性。

  2. AMQP协议:RabbitMQ使用AMQP(Advanced Message Queuing Protocol)作为消息传递的协议。AMQP是一个标准化的消息传递协议,支持多种编程语言和操作系统。

  3. 生产者和消费者:RabbitMQ中的消息发送方称为生产者,消息接收方称为消费者。生产者将消息发送到队列中,而消费者则从队列中接收并处理消息。

  4. 队列:队列是RabbitMQ中存储消息的地方。消息会被顺序写入队列,并按照先进先出的原则进行处理。

  5. 交换机:交换机是RabbitMQ中消息的路由器,它决定了消息应该发送到哪个队列。根据不同的路由策略,交换机可以将消息发送到一个或多个队列。

  6. 绑定:绑定是将交换机和队列关联起来的过程。绑定可以指定特定的路由规则,从而让交换机将消息发送到指定的队列。

  7. 路由策略:RabbitMQ支持多种路由策略,包括直接路由、主题路由和扇形路由等。不同的路由策略适用于不同的场景,可以实现灵活的消息路由。

  8. 可靠性:RabbitMQ提供了多种机制来确保消息的可靠传递,包括持久化、确认机制和发布者确认等。这些机制可以防止消息丢失或重复消费。

2.3RabbitMQ在企业项目中使用场景:

有一个商城项目,可以使用RabbitMQ来实现以下场景:

  1. 异步订单处理:当用户下单后,可以将订单信息封装成消息发送到订单队列中。然后由消费者异步地进行订单处理,例如库存扣减、物流跟踪等。这样可以提高系统的响应速度和可靠性。

  2. 库存同步:在商城项目中,库存是一个重要的资源。可以使用RabbitMQ来实现库存同步,例如将库存变更的消息发送到库存队列中,然后由消费者将库存信息同步到数据库中。

  3. 商品推荐:在商城项目中,推荐系统是一个重要的组件。可以使用RabbitMQ来实现商品推荐的场景,例如将用户浏览历史封装成消息发送到推荐队列中,然后由推荐引擎进行商品推荐。

  4. 优惠券发放:在商城项目中,优惠券是一种常见的促销方式。可以使用RabbitMQ来实现优惠券的发放,例如将优惠券信息封装成消息发送到优惠券队列中,然后由消费者将优惠券发放给符合条件的用户。

  5. 日志收集:商城项目通常需要进行大量的日志记录和统计。可以使用RabbitMQ来实现日志收集,例如将日志信息封装成消息发送到日志队列中,然后由消费者对日志进行分类、统计和分析。

2.3Docker安装部署RabbitMQ

下载镜像:

docker pull rabbitmq:management
docker run -d \ --name my-rabbitmq \

-p 5672:5672 -p 15672:15672 \

-v /home/rabbitmq:/var/lib/rabbitmq \ --hostname my-rabbitmq-host \

-e RABBITMQ_DEFAULT_VHOST=my_vhost \

-e RABBITMQ_DEFAULT_USER=admin \

-e RABBITMQ_DEFAULT_PASS=admin \

--restart=always \ rabbitmq:management

--hostname:主机名(RabbitMQ的一个重要注意事项是它根据所谓的 “节点名称” 存储数据,默认为主机名)

-p:这里有两个端口

-e:指定环境变量: RABBITMQ_DEFAULT_VHOST:默认虚拟机名 RABBITMQ_DEFAULT_USER:默认的用户名

RABBITMQ_DEFAULT_PASS:默认用户名的密码

内容:用于在Docker中运行RabbitMQ的命令。它会创建一个名为"my-rabbitmq"的容器,并映射5672和15672端口到主机上,分别用于AMQP和管理界面访问。容器的数据存储在主机的"/home/rabbitmq"目录下,RabbitMQ的默认虚拟主机为"my_vhost",默认用户名和密码为"admin"。容器会在Docker启动时自动重启。

docker logs my-rabbitmq

Message queue 消息队列--RabbitMQ 【基础入门】_第4张图片

Message queue 消息队列--RabbitMQ 【基础入门】_第5张图片

2.4创建springboot项目嵌套RabbitMQ

Message queue 消息队列--RabbitMQ 【基础入门】_第6张图片

Message queue 消息队列--RabbitMQ 【基础入门】_第7张图片

修改application的配置

consumer.application

server:
    port: 9999
spring:
    application:
        name: xx
    rabbitmq:
        host: 192.168.124.131
        username: springboot
        password: 123456
        port: 5672
        virtual-host: my_vhost

provider.application

server:
    port: 8888
spring:
    application:
        name: xx
    rabbitmq:
        host: 192.168.124.131
        username: springboot
        password: 123456
        port: 5672
        virtual-host: my_vhost

这是一个创建MQ的方法

@Configuration
@SuppressWarnings("all")
public class RabbitConfig {
@Bean
public Queue firstQueue() {
return new Queue("firstQueue");
}
}
Queue("firstQueue");是内置方法

firstQueue是消息队列的名字。

导入指定的包:

Message queue 消息队列--RabbitMQ 【基础入门】_第8张图片

AmqpTemplate pom文件中引入了

    @Autowired
    private AmqpTemplate rabbitTemplate;
    @RequestMapping("/sender")
    @ResponseBody
    public String sendFirst() {
        rabbitTemplate.convertAndSend("firstQueue", "Hello World");
        return "zhu";
    }
传递字符串类型

访问:localhost:8888/sender

报错:Connection refused: connect

解决添加连接的账号密码:

Message queue 消息队列--RabbitMQ 【基础入门】_第9张图片

检查:

Message queue 消息队列--RabbitMQ 【基础入门】_第10张图片

继续访问:localhost:8888/sender

Message queue 消息队列--RabbitMQ 【基础入门】_第11张图片

成功:

构建消费者 Consumer

Message queue 消息队列--RabbitMQ 【基础入门】_第12张图片

Message queue 消息队列--RabbitMQ 【基础入门】_第13张图片

传递实体类型

使用了@Autowired注解来自动注入AmqpTemplate和ObjectMapper对象。AmqpTemplate是Spring提供的一个操作RabbitMQ的工具,可以用来发送和接收消息。ObjectMapper是Jackson库提供的一个工具,可以用来将对象转换为JSON字符串,或者将JSON字符串转换为对象。
sender02方法创建了一个User对象,然后使用ObjectMapper将这个对象转换为JSON字符串,然后发送这个JSON字符串到名为secondQueue的队列中。消费者会接收指定的队列消息使用了log.warn来打印接收到的消息从而消费。

    @RequestMapping("/sender2")
    @ResponseBody
    public String sender2() {
        com.example.provide.User user = new com.example.provide.User("1", "1");
        rabbitTemplate.convertAndSend("secondQueue", user);
        return "zhu2";
    }

package com.example.consumer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@SuppressWarnings("all")
@Component
@Slf4j
@RabbitListener(queues = "firstQueue")
public class SecondReceiver {


    @RabbitHandler
    public void send(User user) {
        log.warn("接收到:" + user);
        }
    }

这里显示不能够这样传递:

Message queue 消息队列--RabbitMQ 【基础入门】_第14张图片

原因是

 SimpleMessageConverter 这个类时,接收到了不支持的消息类型。SimpleMessageConverter 只支持 String、byte[] 和 Serializable 类型的消息内容。

根据异常信息,你传递给它的消息内容是 com.example.provide.User 类型,因此引发了这个异常。你需要将消息内容转换为 SimpleMessageConverter 支持的类型,才能正确地使用它来处理消息。具体的处理方法取决于你的业务场景和需求。

生产者:

    @RequestMapping("/sender2")
    @ResponseBody
    public String sender2() throws JsonProcessingException {
        User user = new User("1", "1");
        // 序列化对象转换为JSON字符串
        String json = objectMapper.writeValueAsString(user);
        rabbitTemplate.convertAndSend("secondQueue", json);
        return "zhu2";
    }

实体:注意实现Serializable

package com.example.provide;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@SuppressWarnings("all")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String username;
private String userpwd;
}

访问响应:

    @RequestMapping("/sender2")
    @ResponseBody
    public String sender2() throws JsonProcessingException {
        User user = new User("1", "1");
        // 序列化对象转换为JSON字符串
        String json = objectMapper.writeValueAsString(user);
        rabbitTemplate.convertAndSend("secondQueue", json);
        return "zhu2";
    }

消费者:

@Component
@Slf4j
@RabbitListener(queues = "secondQueue")
public class SecondReceiver {
    @Autowired
    private ObjectMapper objectMapper;

    @RabbitHandler
    public void send(String json) throws JsonProcessingException {
        User user = objectMapper.readValue(json, User.class);
        // 处理user对象
        log.warn("接收到:" + user.toString());
    }

实体:注意实现Serializable

package com.example.consumer;


import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.io.Serializable;

@SuppressWarnings("all")
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
private String username;
private String userpwd;
}

@Component
@Slf4j
@RabbitListener(queues = "secondQueue")
public class SecondReceiver {
    @Autowired
    private ObjectMapper objectMapper;

    @RabbitHandler
    public void send(String json) throws JsonProcessingException {
        User user = objectMapper.readValue(json, User.class);
        // 处理user对象
        log.warn("接收到:" + user.toString());
    }

        

访问测试:

Message queue 消息队列--RabbitMQ 【基础入门】_第15张图片

Message queue 消息队列--RabbitMQ 【基础入门】_第16张图片

你可能感兴趣的:(rabbitmq,分布式)