RabbitMQ简单入门


RabbitMQ


前期准备

  1. 项目结构
    项目结构
  2. 在父工程的pom文件中引入依赖
<!--AMQP依赖,包含RabbitMQ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  1. 在消息发送方和消息消费方的配置文件中做基本配置
spring:
  rabbitmq:
    host: xxx.xxx.xxx.xxx # 主机名(写自己的)
    port: 5672 # 端口
    virtual-host: / # 虚拟主机
    username: xxx # 用户名(启动docker镜像时的)
    password: xxx # 密码(启动docker镜像时的)
  1. 在消费方注入对象
@Autowired
private RabbitTemplate rabbitTemplate;

简单队列模型

简单队列模型

  • 发送方
    @Test
    void testSimpleQueue(){
        //队列名称
        String queueName="simple.queue";
        
        //消息内容
        String msg = "test simplequeue";
        
        //发送消息
        rabbitTemplate.convertAndSend(queueName,msg);
        System.out.println("消息发送完毕");
    }
  • 消费方
    @RabbitListener(queues = "simple.queue") //queues参数指定队列名称,监听该队列
    public void listenSimple(String msg){
        //输出收到的消息
        System.out.println(msg);
    }

工作队列模型

工作队列模型

  • 发送方
    @Test
    void testWorkQueue(){
        //队列名称
        String queueName="work.queue";

        //消息内容
        String msg = "test workqueue";

        for (int i = 1; i <= 100; i++) {
            //发送消息
            rabbitTemplate.convertAndSend(queueName,msg+i);
        }

        System.out.println("消息发送完毕");
    }
  • 消费方
/**
 * 多个消费者共同消费一个队列
 */
@Component
public class WorkListener {

    /**
     * 消费者1
     * @param msg
     */
    @RabbitListener(queues = "work.queue")
    public void listenWork1(String msg){
        System.out.println("消费者1:"+msg);
    }

    /**
     * 消费者2
     * @param msg
     */
    @RabbitListener(queues = "work.queue")
    public void listenWork2(String msg){
        System.out.println("消费者2:"+msg);
    }
}
  • 补充
    多个消费者(以两个为例)默认会均匀消费消息,这是不太合理的,有时候消费者的消费效率不一样,所以我们应该指定消费策略,在消费者方的配置文件中添加下方红色方框中的”prefetch“配置,只有当消费完前一条的消息才能拿到下一条消息。
    修改消费策略

工作队列模型


发布订阅模型

发布订阅模型


声明队列和交换机

  1. 方式一:配置类型形式(以Fanout类型为例)
@Configuration
public class MqConfig {

    /**
     * 交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        //交换机名称:exchange.fanout
        return new FanoutExchange("exchange.fanout");
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue queue1(){
        //队列名称:fanout.queue1
        return new Queue("fanout.queue1");
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue queue2(){
        //队列名称:fanout.queue2
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定
     */
    @Bean
    //注意参数列表中的参数名要和上面声明的交换机、队列参数名保持一致
    public Binding binding1(FanoutExchange fanoutExchange,Queue queue1){
        return BindingBuilder.bind(queue1).to(fanoutExchange);
    }

    /**
     * 绑定
     */
    @Bean
    //注意参数列表中的参数名要和上面声明的交换机、队列参数名保持一致
    public Binding binding2(FanoutExchange fanoutExchange,Queue queue2){
        return BindingBuilder.bind(queue2).to(fanoutExchange);
    }

}
  1. 方式二:注解形式
    注解形式

Fanout

Fanout

  1. 声明交换机和队列
@Configuration
public class MqConfig {

    /**
     * 交换机
     * @return
     */
    @Bean
    public FanoutExchange fanoutExchange(){
        //交换机名称:exchange.fanout
        return new FanoutExchange("exchange.fanout");
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue queue1(){
        //队列名称:fanout.queue1
        return new Queue("fanout.queue1");
    }

    /**
     * 队列
     * @return
     */
    @Bean
    public Queue queue2(){
        //队列名称:fanout.queue2
        return new Queue("fanout.queue2");
    }

    /**
     * 绑定
     */
    @Bean
    //注意参数列表中的参数名要和上面声明的交换机、队列参数名保持一致
    public Binding binding1(FanoutExchange fanoutExchange,Queue queue1){
        return BindingBuilder.bind(queue1).to(fanoutExchange);
    }

    /**
     * 绑定
     */
    @Bean
    //注意参数列表中的参数名要和上面声明的交换机、队列参数名保持一致
    public Binding binding2(FanoutExchange fanoutExchange,Queue queue2){
        return BindingBuilder.bind(queue2).to(fanoutExchange);
    }

}
  1. 发送方
    @Test
    void testFanout(){
        //交换机名称
        String exchange = "exchange.fanout";

        //消息
        String msg = "test fanout";

        //发送消息到交换机,参数(交换机,routingKey,消息)
        rabbitTemplate.convertAndSend(exchange,"",msg);

        System.out.println("消息发送完毕");
    }
  1. 消费方
@Component
public class FanoutListener {

    @RabbitListener(queues = "fanout.queue1")
    public void listenFanout1(String msg){
        System.out.println("消费者1:"+msg);
    }

    @RabbitListener(queues = "fanout.queue2")
    public void listenFanout2(String msg){
        System.out.println("消费者2:"+msg);
    }
}

Direct

Direct

  • 发送方
    @Test
    void testDirect(){
        //交换机名称
        String exchange = "exchange.direct";

        //消息
        String msg = "test direct";

        //发送消息到交换机,参数(交换机,routingKey,消息)
        rabbitTemplate.convertAndSend(exchange,"这里指定绑定key",msg);

        System.out.println("消息发送完毕");
    }
  • 消费方
@Component
public class DirectListener {

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(name = "direct.queue1"), //指定绑定队列
                    exchange = @Exchange(name = "exchange.direct",type = ExchangeTypes.DIRECT), //指定交换机、交换机类型
                    key = {"blue","red"} //绑定key
            )
    )
    public void listenDirect1(String msg){
        System.out.println("消费者1:"+msg);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(name = "direct.queue2"),
                    exchange = @Exchange(name = "exchange.direct",type = ExchangeTypes.DIRECT),
                    key = {"yellow","red"}
            )
    )
    public void listenDirect2(String msg){
        System.out.println("消费者2:"+msg);
    }
}

Topic

Topic

  • 发送方
    @Test
    void testTopic(){
        //交换机名称
        String exchange = "exchange.topic";

        //消息
        String msg = "test topic";

        //发送消息到交换机,参数(交换机,routingKey,消息)
        rabbitTemplate.convertAndSend(exchange,"这里指定topic",msg);

        System.out.println("消息发送完毕");
    }
  • 消费方
@Component
public class TopicListener {

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(name = "topic.queue1"), //指定绑定队列
                    exchange = @Exchange(name = "exchange.topic",type = ExchangeTypes.TOPIC), //指定交换机、交换机类型
                    key = {"china.#"} //topic
            )
    )
    public void listenTopic1(String msg){
        System.out.println("消费者1:"+msg);
    }

    @RabbitListener(
            bindings = @QueueBinding(
                    value = @Queue(name = "topic.queue2"), //指定绑定队列
                    exchange = @Exchange(name = "exchange.topic",type = ExchangeTypes.TOPIC), //指定交换机、交换机类型
                    key = {"#.news"} //topic
            )
    )
    public void listenTopic2(String msg){
        System.out.println("消费者2:"+msg);
    }
}

消息转换器

使用默认的消息转换器出现的乱码问题

在SpringAMQP的发送方法中,接收消息的类型是Object,也就是说我们可以发送任意对象类型
的消息,SpringAMQP会帮我们序列化为字节后发送;
Spring的对消息对象的处理是由org.springframework.amqp.support.converter.MessageConverter来处理的。而默认实现是SimpleMessageConverter,基于JDK的ObjectOutputStream完成序列化。
众所周知,JDK序列化存在下列问题:

  • 数据体积过大
  • 有安全漏洞
  • 可读性差

此时我们发送一个对象消息

    @Test
    public void testSendMap() throws InterruptedException {
        // 准备消息
        Map<String,Object> msg = new HashMap<>();
        msg.put("name", "小明");
        msg.put("age", 30);
        msg.put("sex", "男");
        // 发送消息
        rabbitTemplate.convertAndSend("object.queue", msg);
    }

获取消息变成乱码
在这里插入图片描述

解决方案

使用JSON方式来做序列化和反序列化

  • 在发送方引入依赖
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    <version>2.9.10</version>
</dependency>
  • 在启动类配置一个消息转换器
@Bean
public MessageConverter jsonMessageConverter(){
    return new Jackson2JsonMessageConverter();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值