五阶段--RabbitMQ - Spring boot 整合

一 spring boot 项目整合rabbitmq的准备

 

RabbitMQ - Spring boot 整合_wanght笔记-CSDN博客

全程保证虚拟机开启docker和rabbitmq服务

新建rabbitmq-spring项目

下一步:搜索rabbitmq依赖并finish添加

第一步:pom.xml文件修改版本为2.3.2.RELEASE

第二步:配置文件修改后缀为.yml文件,进行rabbitmq的连接配置

spring:
  rabbitmq:
    host: 192.168.64.140    #wht6.cn
    port: 5672
    username: admin
    password: admin 
    #virtual-host: vh-rs  #如果连接老师的服务需要创建空间名

二spring boot 整合rabbitmq,对其几种模式进行测试

目录

一 spring boot 项目整合rabbitmq的准备

新建rabbitmq-spring项目

二spring boot 整合rabbitmq,对其几种模式进行测试

1 简单模式:一对一发送消息

2 工作模式: 多个消费者轮询接收消息

3  发布和订阅模式:广播模式,多个消费者同时获得消息

4  路由模式:发送消息给绑定的关键词

5 主题模式:发送消息给指定的关键词绑定者


1 简单模式:一对一发送消息

第一步:新建一个m1包,不使用自带的启动类也可以删除掉,并创建独立启动类名为Main,和消息生产者类以及消息消费者类

  •  消息生产者类:
package cn.tedu.rabbitmqspring.m1;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

//消息生产者,向helloworld 队列发送消息
@Component
public class Producer {
    @Autowired
    private AmqpTemplate t;
    //自定义方法,需要自己手动调用完成发送
    public void send(){
        //转换并发送
        t.convertAndSend("helloworld","Hello world!");
    }
}
  • 消息消费者类:
package cn.tedu.rabbitmqspring.m1;

import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

//消息消费者,从helloworld队列接收消息
@Component
//@RabbitListener(queues = "helloworld")
public class Consumer {
    //@RabbitHandler  //指定处理消息的方法
    /*每个 @RabbitListener 注解,都会注册启动一个消费者
    * //也可以直接放在指定的消息处理方法上,
      //方便更直接的处理不同队列的消息处理方法,而不用创建多个类了*/
    @RabbitListener(queues = "helloworld")
    public void receive(String s){
        System.out.println("收到: "+s);
    }
}
  • Main启动类,并提供消息的监听和处理方法
package cn.tedu.rabbitmqspring.m1;

import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;

//spring启动类
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
    //创建 Queue 实例,封装队列参数
    @Bean
    public Queue helloworldQueue(){
       // return new Queue("helloworld");//默认持久队列,true
        return new Queue("helloworld",false);//设为非持久
    }
    //添加测试代码,调用生产者发送消息
    @Autowired
    private Producer p;

    /*spring 执行流程:
    *    包扫描创建实例-->完成所有的依赖注入 --> @PostConstruct -->后续流程*/
    @PostConstruct
    public void test(){
        //这里代码执行时,自动配置类有可能没有创建队列,消息者可能也没有启动,
        //第一次执行可能丢失消息
        p.send();
    }
}

第二步:此处使用自己的服务,虚拟机重启docker,重启rabbitmq,登录rabiitmq服务,后台启动Main启动类

注意:第一次启动可能丢失消息,需要再次启动,才能收到消息

2 工作模式: 多个消费者轮询接收消息

第一步: 新建m2包,复制m1包的三个类启动类名为Main,和消息生产者类以及消息消费者类

第二步:修改生产者手动发送消息,队列名为task_queue

//如果发送非持久消息,需要以下设置
//t.convertAndSend("task_queue",s,消息预处理器,可以重新设置消息的属性);

 第三步:多个消费者负载均衡  ,此处是两个接收消息

package cn.tedu.rabbitmqspring.m2;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

//消息消费者,从task_queue队列接收消息
//两个消费者共享一个队列
@Component
//@RabbitListener(queues = "task_queue")
public class Consumer {
    //@RabbitHandler  //指定处理消息的方法
    /*每个 @RabbitListener 注解,都会注册启动一个消费者
    * //也可以直接放在指定的消息处理方法上,
      //方便更直接的处理不同队列的消息处理方法,而不用创建多个类了*/
    @RabbitListener(queues = "task_queue")
    public void receive1(String s){
        System.out.println("消费者1收到: "+s);
    }
    @RabbitListener(queues = "task_queue")
    public void receive2(String s){
        System.out.println("消费者2收到: "+s);
    }
}

 第四步:修改Main启动类下的队列名  ,并设为持久队列

  • 修改发送消息的方法
    //添加测试代码,调用生产者发送消息
    @Autowired
    private Producer p;

    /*spring 执行流程:
    *    包扫描创建实例-->完成所有的依赖注入 --> @PostConstruct -->后续流程自动配置类*/
    @PostConstruct
    public void test(){
//        new Thread(new Runnable() { //启动一个线程,在这里面发送消息
//            @Override
//            public void run() {
//                p.send();
//            }
//        }).start();
        //如果发送很多消息,使用lambda表达式,是匿名内部类的简化语法
        new Thread(() -> p.send()).start();
        //如果是很多消息,p.send每次只发一条,所以需要把发消息的p.send用大括号括起来
    }
}

第五步:启动m2包的Main启动类,发送消息,两个接收者会轮询接收消息

 

3  发布和订阅模式:广播模式,多个消费者同时获得消息

第一步:新建m3包,复制m1包的三个类启动类名为Main,和消息生产者类以及消息消费者类

第二步:修改生产者的编码,给指定交换机发送消息

 第三步:消费者设为两个,绑定交换交换机和队列,此处并没有创建交换机,而是在启动类Main中创建

package cn.tedu.rabbitmqspring.m3;

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.Component;

//消息消费者,绑定接收消息
//两个消费者共享一个队列
@Component
public class Consumer {

    //绑定交换机(exchange-@Exchange),和队列(value-@Queue)
    @RabbitListener(bindings =@QueueBinding(
            value = @Queue, //队列不写参数时的格式:随机命名,非持久,独占,自动删除
            exchange = @Exchange(name = "logs",declare = "false")//declare = "false",使用已经存在的交换机而不创建交换机
    ))
    public void receive1(String s){
        System.out.println("消费者1收到: "+s);
    }

    @RabbitListener(bindings =@QueueBinding(
            value = @Queue,
            exchange = @Exchange(name = "logs",declare = "false")
    ))
    public void receive2(String s){
        System.out.println("消费者2收到: "+s);
    }
}

第四步: 创建Fanout交换机,启动测试,发送消息,两个消费者都能同时收到同样的消息

4  路由模式:发送消息给绑定的关键词

第一步: 新建m4包,复制m3包的三个类启动类名为Main,和消息生产者类以及消息消费者类

第二步:修改生产者的编码,给指定路由交换机发送消息

package cn.tedu.rabbitmqspring.m4;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Scanner;

//消息生产者,向helloworld 队列发送消息
@Component
public class Producer {
    @Autowired
    private AmqpTemplate t;
    //自定义方法,需要自己手动调用完成发送
    public void send(){
        while (true){
            System.out.println("输入消息:  ");
            String s = new Scanner(System.in).nextLine();
            System.out.println("输入关键词:  ");
            String k = new Scanner(System.in).nextLine();
            t.convertAndSend("direct_logs",k,s);

        }
    }
}

第三步:消费者设为两个,绑定路由换交换机和队列,并绑定key键,此处并没有创建交换机,而是在启动类Main中创建

package cn.tedu.rabbitmqspring.m4;

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.Component;

//消息消费者,绑定接收消息
//两个消费者共享一个队列
@Component
public class Consumer {

    //绑定交换机(exchange-@Exchange),和队列(value-@Queue)
    @RabbitListener(bindings =@QueueBinding(
            value = @Queue, //队列不写参数时的格式:随机命名,非持久,独占,自动删除
            //declare = "false",使用已经存在的交换机而不创建交换机
            exchange = @Exchange(name = "direct_logs",declare = "false"),
            key ={"error"}   //设置绑定关键词
    ))
    public void receive1(String s){
        System.out.println("消费者1收到: "+s);
    }

    @RabbitListener(bindings =@QueueBinding(
            value = @Queue,
            exchange = @Exchange(name = "direct_logs",declare = "false"),
            key = {"error","info","warning"}
    ))
    public void receive2(String s){
        System.out.println("消费者2收到: "+s);
    }
}

第四步:在Main启动类下创建路由交换机,启动测试

package cn.tedu.rabbitmqspring.m4;

import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;

//spring启动类
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
    //创建 路由 交换机
    @Bean
    public DirectExchange logsExchange(){
        return new DirectExchange("direct_logs",false,false);
    }
    //添加测试代码,调用生产者发送消息
    @Autowired
    private Producer p;

    /*spring 执行流程:
    *    包扫描创建实例-->完成所有的依赖注入 --> @PostConstruct -->后续流程自动配置类*/
    @PostConstruct
    public void test(){
        new Thread(() -> p.send()).start();
    }
}
  • 测试效果:

5 主题模式:发送消息给指定的关键词绑定者

第一步: 新建m4包,复制m3包的三个类启动类名为Main,和消息生产者类以及消息消费者类

第二步:修改生产者的编码,给指定路由交换机发送消息

package cn.tedu.rabbitmqspring.m5;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Scanner;

//消息生产者,向helloworld 队列发送消息
@Component
public class Producer {
    @Autowired
    private AmqpTemplate t;
    //自定义方法,需要自己手动调用完成发送
    public void send(){
        while (true){
            System.out.println("输入消息:  ");
            String s = new Scanner(System.in).nextLine();
            System.out.println("输入关键词:  ");
            String k = new Scanner(System.in).nextLine();
            t.convertAndSend("topic_logs",k,s);

        }
    }
}

第三步:消费者设为两个,绑定主题交换机和队列,并绑定key键,此处并没有创建交换机,而是在启动类Main中创建

package cn.tedu.rabbitmqspring.m5;

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.Component;

//消息消费者,绑定接收消息
//两个消费者共享一个队列
@Component
public class Consumer {

    //绑定交换机(exchange-@Exchange),和队列(value-@Queue)
    @RabbitListener(bindings =@QueueBinding(
            value = @Queue, //队列不写参数时的格式:随机命名,非持久,独占,自动删除
            //declare = "false",使用已经存在的交换机而不创建交换机
            exchange = @Exchange(name = "topic_logs",declare = "false"),
            key ={"*.orange.*"}   //设置绑定关键词
    ))
    public void receive1(String s){
        System.out.println("消费者1收到: "+s);
    }

    @RabbitListener(bindings =@QueueBinding(
            value = @Queue,
            exchange = @Exchange(name = "topic_logs",declare = "false"),
            key = {"*.*.rabbit","lazy.#"}
    ))
    public void receive2(String s){
        System.out.println("消费者2收到: "+s);
    }
}

第四步:在Main启动类下创建主题交换机,启动测试

package cn.tedu.rabbitmqspring.m5;

import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;

//spring启动类
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
    //创建 主题 交换机
    @Bean
    public TopicExchange logsExchange(){
        return new TopicExchange("topic_logs",false,false);
    }
    //添加测试代码,调用生产者发送消息
    @Autowired
    private Producer p;

    /*spring 执行流程:
    *    包扫描创建实例-->完成所有的依赖注入 --> @PostConstruct -->后续流程自动配置类*/
    @PostConstruct
    public void test(){
        //如果发送很多消息,使用lambda表达式,是匿名内部类的简化语法
        new Thread(() -> p.send()).start();
    }
}
  • 测试效果:

6 RPC模式

客户端

package cn.tedu.rabbitmqspring.m6;

import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.util.UUID;
@Component
public class Client {
    @Autowired
    private AmqpTemplate t;

    @Value("#{rndQueue.name}")
    private String replyTo;

    public void send(int n){
        t.convertAndSend("rpc-queue", n, ( message) -> {
            MessageProperties p = message.getMessageProperties();
            p.setReplyTo(replyTo);//返回队列名
            p.setCorrelationId(UUID.randomUUID().toString());//返回关联id
            return message;
        });
    }
    @RabbitListener(queues = "#{rndQueue.name}")
    public void receive(long r, @Header(name = AmqpHeaders.CORRELATION_ID) String cid){
        System.out.println(cid+"~~结果: "+r);
    }

}

服务端:

package cn.tedu.rabbitmqspring.m6;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
public class Server {
    /*如果处理消息的方法不是void ,由返回值,
    * 那么 Spring 会把返回值,通过返回队列发回到客户端,并携带关联id*/
    @RabbitListener(queues = "rpc-queue")
    public long receive(int n){
        long r =f(n);
        return r;
    }

    private long f(int n) {
        long a=1;
        long b=2;
        for (int i = 3; i <=n ; i++) {
            b = a+b;
            a = b-a;
        }
        return b;
    }
}

启动类及调用客户端方法

package cn.tedu.rabbitmqspring.m6;

import org.springframework.amqp.core.Queue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import javax.annotation.PostConstruct;
import java.util.Scanner;
import java.util.UUID;

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class,args);
    }
    /**
     * SPEL --
     * */
    //创建随机队列对象,交给spring容器管理,对象名就叫rndQueue
    @Bean
    public Queue rndQueue(){
        return new Queue(UUID.randomUUID().toString(),
                false,true,true);
    }
    @Autowired
    private Client client;

    @PostConstruct
    public void test(){
        new Thread(()->{
            while(true){
                System.out.println("求第几个斐波那契数: ");
                int n = new Scanner(System.in).nextInt();
                client.send(n);
            }
        }).start();
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值