マイクロサービス: springboot で 03-rabbitmq を使用する方法 (パート 2)

目次

序文: 上記に送信

4. 6つのモードの実際の動作(続き)

4.4 ルーティングモード: 

---> 4.4.1 コンシューマ構成クラス

---> 4.4.2 消費者コード

--->4.4.3 プロデューサーコード

4.5 テーマモード:(ルーティングアップグレードバージョン)

---> 4.5.1 コンシューマ構成クラス

---> 4.5.2 消費者コード

---> 4.5.3 プロデューサーコード

---> 4.5.4 テスト結果

4.6 RPC 非同期呼び出しモード (あまり使用されません) 

---> 4.6.0 mq の簡単な歴史を見つけるのは非常に興味深いです: メッセージミドルウェアの開発の歴史は興味深い歴史的な物語です

---> 4.6.1 コンシューマ構成クラス

---> 4.6.2 プロデューサー設定クラス

---> 4.6.3 コンシューマコード

---> 4.6.4 プロデューサーコード

---> 4.6.5 効果を実感する

記事の概要:


序文: 上記に送信

springboot でマイクロサービス 02-rabbitmq を使用する方法 (その 1)

4. 6つのモードの実際の動作(続き)

4.4 ルーティングモード: 

---> 4.4.1 コンシューマ構成クラス

package cn.pingzhuyan.rabbitmq.config;

import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * rabbitmq的默认手动确认模式
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Configuration
public class RabbitConfig {

    /**
     * 创建(声明)一个简单队列
     * @return
     */
    @Bean
    public Queue helloQueue(){
//        return new Queue("PZY",true,false,false);
        return new Queue("PZY");
    }

    /**
     * 创建radioFanout交换机
     * 消费者需要绑定此交换机
     * @return
     */
    @Bean
    public FanoutExchange radioFanout(){
        return new FanoutExchange("PZY_RADIO",false,false);
    }

    /**
     * 路由模式 指定路由交换机
     * 指定接收路由键
     * @return
     */
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange("PZY_DIRECT",false,false);
    }

}

---> 4.4.2 消費者コード

package cn.pingzhuyan.rabbitmq.directM4;

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;

/**
 * 路由交换机消费者
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Component
public class DirectM4Consumer {

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue,  //不写就是随机队列, false true true
            exchange = @Exchange(name = "PZY_DIRECT", declare = "false"),//交换机(PZY_RADIO, 不创建并使用已经存在的交换机)
            key = {"pzy1", "pzy2"}
    ))
    public void radioFanoutMessage1(String msg) {
        System.out.printf("消费者1接收到<1/2>: %s\n", msg);
    }

    @RabbitListener(bindings = @QueueBinding(
            value = @Queue,  //不写就是随机队列, false true true
            exchange = @Exchange(name = "PZY_DIRECT", declare = "false"),//交换机(PZY_RADIO, 不创建并使用已经存在的交换机)
            key = {"pzy3", "pzy4"}
    ))
    public void radioFanoutMessage2(String msg) {
        System.out.printf("消费者2接收到<3/4>: %s\n", msg);
    }

}

--->4.4.3 プロデューサーコード

package cn.pingzhuyan.rabbitmq.directM4;

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

import java.util.Random;

/**
 * 路由交换机生产者
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Component
public class DirectM4Provider {

    @Autowired
    private AmqpTemplate amqpTemplate;


    @Async
    @Scheduled(cron = "*/1 * * * * ?")
    public void directSend01() {

        int num = new Random().nextInt(4) + 1;//生成1-4的随机数

        System.out.println("生产者1: <发布和订阅模式>定时(1次/s)发送 -> " + "我是消息,编号是: " + num);

        amqpTemplate.convertAndSend("PZY_DIRECT", "pzy" + num, "我是消息,编号是: " + num);
    }


}

4.5 テーマモード:(ルーティングアップグレードバージョン)

---> 4.5.1 コンシューマ構成クラス

    /**
     * 主题模式(升级版路由) 指定路由交换机
     * 指定接收路由键表达式
     * @return
     */
    @Bean
    public TopicExchange topicExchange(){
        return new TopicExchange("PZY_TOPIC",false,false);
    }

---> 4.5.2 消費者コード

//テスト 4

//1. pzy.pzy.pzy 1 と 2 の両方が受信可能

//2. aaa.pzy.bbb 1 は受信可能

//3. pzy.aaa.bbb.ccc 2 は受信可能

//4. aaa.bbb.pzy 2 は受信可能

package cn.pingzhuyan.rabbitmq.topicM5;

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;

/**
 * 路由交换机消费者
 * 测试四种
 * 1. pzy.pzy.pzy     1和2 都能收到
 * 2. aaa.pzy.bbb     1能收到
 * 3. pzy.aaa.bbb.ccc 2能收到
 * 4. aaa.bbb.pzy     2能收到
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Component
public class TopicM5Consumer {

    /**
     * 消费者1
     *
     * @param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue,  //不写就是随机队列, false true true
            exchange = @Exchange(name = "PZY_TOPIC", declare = "false"),//交换机(PZY_RADIO, 不创建并使用已经存在的交换机)
            key = {"*.pzy.*"}
    ))
    public void radioFanoutMessage1(String msg) {
        System.out.printf("消费者1接收到: %s\n", msg);
    }

    /**
     * 消费者2
     *
     * @param msg
     */
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue,  //不写就是随机队列, false true true
            exchange = @Exchange(name = "PZY_TOPIC", declare = "false"),//交换机(PZY_RADIO, 不创建并使用已经存在的交换机)
            key = {"pzy.#", "*.*.pzy"}
    ))
    public void radioFanoutMessage2(String msg) {
        System.out.printf("消费者2接收到: %s\n", msg);
    }

}

---> 4.5.3 プロデューサーコード

@PostConstruct による Portal ===> の説明: クラスのロード開始時のメソッド実行のいくつかの実装 

package cn.pingzhuyan.rabbitmq.topicM5;

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

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

/**
 * 主题模式生产者
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Component
public class TopicM5Provider {

    @Autowired
    private AmqpTemplate amqpTemplate;
    
    @PostConstruct
    public void topicSend01() {

        for (; ; ) {
            System.out.println("请输入路由键: ");
            String routingKey = new Scanner(System.in).nextLine();

            /*中断测试,启动程序完成*/
            if ("exit".equalsIgnoreCase(routingKey)) break;

            System.out.println("请输入消息: ");
            String message = new Scanner(System.in).nextLine();

            System.out.println("生产者1: <发布和订阅模式>发送 -> " + message + "路由键是: " + routingKey);

            amqpTemplate.convertAndSend("PZY_TOPIC", routingKey, message);
        }
    }
}

---> 4.5.4 テスト結果

4.6 RPC 非同期呼び出しモード (あまり使用されません) 

【個人的な理解なので、気に入らない場合はスプレーしないでください】

   成熟したrpcフレームワークであるdubbo Netflix (feign、ribbon、Hystrix)、gRpcなどの機能がより充実しており、マイクロサービスアーキテクチャにおけるサービス間の内部通信には欠かせない技術となっています。

   Rabbitmq を使用する rpc モードのパフォーマンスのボトルネックはそこにあります。mq がクラッシュすると、サービス システム全体が利用できなくなります。mqの簡単な歴史を調べてみる
   と、このテクノロジーはマイクロサービスが誕生する前に登場していたはずです。このモードを理解している人は少ないです。理由

---> 4.6.0 mq の簡単な歴史を見つけるのは非常に興味深いです: メッセージ ミドルウェアの開発の歴史は興味深い歴史的な物語です

---> 4.6.1 コンシューマ構成クラス

2 番目のランダム キューは、ステートメントを書かずにどこにでも配置できます。 

   /**
     * RPC异步调用模式(用的最少)
     * @return
     */
    @Bean
    public Queue sendQueue() {
        return new Queue("PZY_PRC", false);
    }

    /**
     * 声明PRC一个随机队列  (生产者需要监听这个队列 收到回执消息)
     * @return
     */
    @Bean
    public Queue rpcRandomQueue() {
        return new Queue(UUID.randomUUID().toString(), false);
    }

---> 4.6.2 プロデューサー設定クラス

 取得する必要があるキューの名前は、 Bean #{rpcRandomQueue.name}を取得するメソッドを提供します。

package cn.pingzhuyan.rabbitmq.config;

import org.springframework.amqp.core.Queue;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.UUID;

/**
 * 生产者
 * rabbitmq的默认手动确认模式
 * <p>
 * 只需要声明一个随机队列 绑定生成的验证码
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Configuration
public class RabbitConfig {

    /**
     * 声明一个随机队列
     *
     * @return
     */
    @Bean
    public Queue rpcRandomQueue() {
        return new Queue(UUID.randomUUID().toString(), false);
    }

}

---> 4.6.3 コンシューマコード

 ビジネスコードはカジュアルで、主な目的はこのビジネス処理の結果を書き、合計を書き、乱数を書き、文字を推測することです。

package cn.pingzhuyan.rabbitmq.RpcM6;

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

import java.util.Random;

/**
 * Rpc模式 消费者
 *
 * 其实也是生产者 将收到的消息放入随机队列
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */
@Component
public class RpcM6Consumer {

    @RabbitListener(queues = "PZY_PRC")
    public String getAuthCode(int length) {

        String authCode = makeAuthCode(length);

        System.out.printf("由消费者1制作完成: %s \n", authCode);

        return authCode;
    }

    @RabbitListener(queues = "PZY_PRC")
    public String getAuthCode1(int length) {
        String authCode = makeAuthCode(length);

        System.out.printf("由消费者1制作完成: %s \n", authCode);

        return authCode;
    }

    /**
     * 制作验证码
     *
     * @param length
     * @return
     */
    private String makeAuthCode(int length) {
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < 26; i++) {
            builder.append((char) ('a' + i));
            builder.append((char) ('A' + i));

            if (i < 10) builder.append(i);

        }
        String line = builder.toString();
        StringBuilder b = new StringBuilder();
        Random rand = new Random();
        for (int i = 0; i < length; i++) {
            b.append(line.charAt(rand.nextInt(line.length())));
        }

        try {
            Thread.sleep(rand.nextInt(2000));//阻塞0-5000ms
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.printf("生成 %s 位数验证码, ", length);
        return b.toString();
    }


}

---> 4.6.4 プロデューサーコード

package cn.pingzhuyan.rabbitmq.RpcM6;


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.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Random;

import java.util.UUID;

/**
 * rpc模式 生产者
 * <p>
 * 也是消费者 从绑定的随机队列中接收到消息
 *
 * @author pzy
 * @version 0.1.0
 * @description: TODO
 */

@Component
@EnableAsync
@EnableScheduling
public class RpcM6Provider {

    @Autowired
    private AmqpTemplate amqpTemplate;


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


    /**
     * 定时操作 生成随机位数的验证码
     */
    @Async
    @Scheduled(cron = "*/5 * * * * ?")
    public void topicSend01() {

        int length = new Random().nextInt(19) + 1;//自然数
        System.out.printf("验证码生成器(随机生成位数): %s \n", length);
//        if (length <= 0) length = 1;

        amqpTemplate.convertAndSend("PZY_PRC", length, message -> {
            MessageProperties messageProperties = message.getMessageProperties();
            messageProperties.setReplyTo(rpcRandomQueue);
            messageProperties.setCorrelationId(UUID.randomUUID().toString());
            return message;
        });
    }

    /**
     * 生产者-> 消费者  接收绑定了消息的随机队列
     * 然后进行后面逻辑业务
     * @param authCode
     * @param correlationId
     */
    @RabbitListener(queues = "#{rpcRandomQueue.name}")
    public void receive(String authCode, @Header(name = AmqpHeaders.CORRELATION_ID) String correlationId) {

        System.out.println("生产者: 收到关联id号-> " + correlationId + "的验证码是: " + authCode);
    }


}

---> 4.6.5 効果を実感する

プロデューサーサービス 

 消費者サービス


記事の概要:

この時点で、rabbitmq を統合する springboot の基本的なデモは終了し、コードが 1 行ずつ入力され、実際のテストが成功するという結果が得られます。

今後追加される可能性のある他の書き方もありますので、コメントを歓迎します

おすすめ

転載: blog.csdn.net/pingzhuyan/article/details/131554699