RabbitMQ消息队列的入门实践

需求

客户端向RabbitMQ中的调用队列发送消息,服务端从调用队列取出消息并将结果返回给RabbitMQ中的返回队列,假如客户端的消息请求是计算第几位菲波拉契数的值。

入门版

添加依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>cn.tedu</groupId>
    <artifactId>rabbitmq-spring</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>rabbitmq-spring</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</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>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml配置文件

spring:
  rabbitmq:
    host: wht6.cn
    port: 5672
    username: admin
    password: admin
    virtual-host: vh-zl

注意:如果用的是别人的rabbitmq服务的话,则需要添加 virtual-host,并且还需要去服务里面手动添加配置。

客户端

只是创建了普通队列。

package cn.tedu.sp09.m6;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.Scanner;
import java.util.UUID;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeoutException;
/**
 * @Author 作者:小龙猿
 * @Project 项目:springcloud1
 * @Time 时间:2021/9/18 10:45
 */
public class Client {
    public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
        System.out.println("求第几个菲波拉契数:");
        int n = new Scanner(System.in).nextInt();
        long r = f(n);
        System.out.println("第"+n+"个菲波拉契数:"+r);

    }

    private static long f(int n) throws IOException, TimeoutException, InterruptedException {
        //客户端准备阻塞队列集合
        ArrayBlockingQueue<Long> abq = new ArrayBlockingQueue<>(10);
        //连接
        ConnectionFactory f = new ConnectionFactory();
        f.setHost("wht6.cn");
        f.setPort(5672);
        f.setUsername("admin");
        f.setPassword("admin");
        Channel c = f.newConnection().createChannel();
        //创建调用队列,调用队列和返回队列是消息中间件里面的
        c.queueDeclare("rpc-queue", false, false, false, null);
        //创建返回队列,队列名随机,存放返回结果
        String replayTo = c.queueDeclare().getQueue();
        //产生一个关联id,用于指定将结果返回给哪个用户
        String cid = UUID.randomUUID().toString();
        //发送调用信息,携带两个参数:返回队列名和关联id
        AMQP.BasicProperties prop = new AMQP.BasicProperties.Builder().replyTo(replayTo).correlationId(cid).build();
        c.basicPublish("", "rpc-queue",prop, (n+"").getBytes());
        //执行其它运算
        System.out.println("执行其它运算");
        //需要结果时,从返回队列接收计算结果
        DeliverCallback deliverCallback = (s, delivery) -> {
            //消费者线程处理计算结果
            // 判断delivery中的关联id是不是刚才发送的关联id
            if (cid.equals(delivery.getProperties().getCorrelationId())){
                String s1 = new String(delivery.getBody());//获取返回结果
                //把结果放入 BlockingQueue
                abq.add(Long.valueOf(s1));
            }
        };
        CancelCallback cancelCallback = s -> {

        };
        c.basicConsume(replayTo, true,deliverCallback,cancelCallback);
        //主线程中,从BlockingQueue 获取数据
        return abq.take();//返回客户端阻塞队列里面的结果
    }
}

服务端

package cn.tedu.sp09.m6;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
/**
 * @Author 作者:小龙猿
 * @Project 项目:springcloud1
 * @Time 时间:2021/9/18 14:04
 */
public class Server {
    public static void main(String[] args) throws IOException, TimeoutException {
        //连接
        ConnectionFactory f = new ConnectionFactory();
        f.setHost("wht6.cn");
        f.setPort(5672);
        f.setUsername("admin");
        f.setPassword("admin");
        Channel c = f.newConnection().createChannel();
        //创建调用队列rpc-queue,调用队列和返回队列是消息中间件里面的
        c.queueDeclare("rpc-queue", false, false, false, null);
        //从rpc-queue 接收调用信息
        DeliverCallback deliverCallback = (s,delivery)->{
            //求出菲波拉契数
            //从delivery取出: n,返回队列名,关联id
            Integer n = Integer.valueOf(new String(delivery.getBody()));
            String replyTo = delivery.getProperties().getReplyTo();
            String cid = delivery.getProperties().getCorrelationId();
            System.out.println("求第"+n+"个菲波拉契数");
            long r = fbnq(n);
            //把结果发回到返回队列,携带关联id参数
            AMQP.BasicProperties prop = new AMQP.BasicProperties.Builder()
                    .correlationId(cid)
                    .build();
            c.basicPublish("", replyTo, prop, (r+"").getBytes());
        };
        CancelCallback cancelCallback = s -> {};
        c.basicConsume("rpc-queue", true,deliverCallback,cancelCallback);
    }
    public static long fbnq(int n){
        if (n == 1 || n == 2){
            return 1;
        }
        long a = 1;
        long b = 1;
        for (int i = 3; i < n; i++) {
            b = a + b;
            a = b - a;
        }
        return b;
    }
}

进阶版

入门版都是自己创建队列并携带参数信息,进阶版就把这些操作交给了spring去处理。

主程序

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;
/**
 * @Author 作者:小龙猿
 * @Project 项目:rabbitmq-api
 * @Time 时间:2021/9/18 14:58
 */
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
    /*
   这个对象放入spring容器,对象名叫:rndQueue
   SPEL --- Spring Expression Language
   直接访问 spring 容器中的对象
   #{rndQueue.name}
   OGNL --- Object Graph Navigation Language
   Struts2 中的一种标记
   ${}
    */
    @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.print("求第几个菲波拉契数:");
                int n = new Scanner(System.in).nextInt();
                client.send(n);
            }
        }).start();
    }
}

客户端

package cn.tedu.rabbitmqspring.m6;
import org.springframework.amqp.core.AmqpTemplate;
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;
/**
 * @Author 作者:小龙猿
 * @Project 项目:rabbitmq-api
 * @Time 时间:2021/9/18 14:58
 */
@Component
public class Client {
    @Autowired
    private AmqpTemplate t;
    //使用 SPEL 表达式获取随机队列名: "#{rndQueue.name}"
    @Value("#{rndQueue.name}")
    private String replyTo;
    //发送调用数据时, 携带随机队列名和correlationId
    public void send(int n){
        t.convertAndSend("rpc-queue", n,(message)->{
            MessageProperties p = message.getMessageProperties();
            p.setReplyTo(replyTo);
            p.setCorrelationId(UUID.randomUUID().toString());
            return message;
        });
    }
    //从随机队列接收计算结果,从随机队列接收调用结果, 并获取correlationId
    @RabbitListener(queues = "#{rndQueue.name}")
    public void receive(long r, @Header(name = AmqpHeaders.CORRELATION_ID)String cid){
        System.out.println("结果:"+r);
    }
}

服务端

package cn.tedu.rabbitmqspring.m6;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * @Author 作者:小龙猿
 * @Project 项目:rabbitmq-api
 * @Time 时间:2021/9/18 15:26
 */
@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) {
        if (n ==1 || n == 2)
            return 1;
        return f(n-1)+f(n-2);
    }   
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值