SpringCloud Stream RabbitMQ動態(tài)路由Key問題
前言
這里有個業(yè)務(wù)是這樣的,我需要在不同的操作后給用戶發(fā)送不同的郵件,由于比較耗時所以引入消息中間件,不同的郵件對應(yīng)的消息類型是不一樣的,所以需要生產(chǎn)者往隊列里發(fā)送數(shù)據(jù)時綁定好路由key,例如:

圖里表示交換機根據(jù)路由key綁定了不同的隊列。
要達(dá)到這種效果,首先消費者肯定是可以根據(jù)路由key來決定消息是不是發(fā)送給自己的,對于生產(chǎn)者則需要用到routingKeyExpression 來決定往哪個路由key發(fā)送數(shù)據(jù)(大概是這個意思)。
然后就是stream中的group其實對應(yīng)到rabbitMQ中就是隊列的概念,所以我們這里設(shè)置兩個不同的group來對應(yīng)到不同的隊列,區(qū)分開業(yè)務(wù);
例子
這里我定義了兩個服務(wù)對應(yīng)消費者和生產(chǎn)者。
生產(chǎn)者
spring:
application:
name: producer
cloud:
stream:
binders: # 綁定MQ服務(wù)信息(此處我們是RabbitMQ)
etpmsRabbitMQ: # 給Binder定義的名稱,?于后?的關(guān)聯(lián)
type: rabbit # MQ類型,如果是Kafka的話,此處配置kafka
environment: # MQ環(huán)境配置(?戶名、密碼等)
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: xxxxxx
bindings: # 關(guān)聯(lián)整合通道和binder對象
output: # output是我們定義的通道名稱,此處不能亂改
destination: testExchange # 要使?的Exchange名稱(消息隊列主題名稱)
content-type: text/plain # application/json # 消息類型設(shè)置,?如json
binder: etpmsRabbitMQ # 關(guān)聯(lián)MQ服務(wù)
rabbit:
bindings:
output:
producer:
# 生產(chǎn)者配置RabbitMq的動態(tài)路由鍵
routingKeyExpression: headers.typepackage top.chenyt.producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
/**
* @author yantao.chen
*/
@Service
public class ProviderService {
/**
* 將MessageChannel的封裝對象Source注?到這?使?
*/
@Autowired
private Source source;
public void sendMessage(String content, String type) {
// 向mq中發(fā)送消息(并不是直接操作mq,應(yīng)該操作的是spring cloud stream)
// 使?通道向外發(fā)出消息(指的是Source??的output通道)
source.output().send(MessageBuilder.withPayload(content).setHeader("type",type).build());
}
}
package top.chenyt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.cloud.stream.messaging.Source;
/**
* @ClassName etpms-parent
* @Author Jinondo
* @Date 2022/1/31 12:42
*/
@SpringBootApplication
@Slf4j
@EnableBinding({Source.class})
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
主要是yml配置添加:routingKeyExpression: headers.type
發(fā)送消息的時候setHeader一下
消費者
spring:
application:
name: consumer
cloud:
stream:
binders: # 綁定MQ服務(wù)信息(此處我們是RabbitMQ)
etpmsRabbitMQ: # 給Binder定義的名稱,?于后?的關(guān)聯(lián)
type: rabbit # MQ類型,如果是Kafka的話,此處配置kafka
environment: # MQ環(huán)境配置(?戶名、密碼等)
spring:
rabbitmq:
host: localhost
port: 5672
username: admin
password: xxxxx
bindings: # 關(guān)聯(lián)整合通道和binder對象
input: # input是我們定義的通道名稱,此處不能亂改
destination: testExchange # 要使?的Exchange名稱(消息隊列主題名稱)
content-type: text/plain # application/json # 消息類型設(shè)置,?如json,自動將對象轉(zhuǎn)為json
binder: etpmsRabbitMQ # 關(guān)聯(lián)MQ服務(wù)
group: register
my-input:
destination: testExchange # 要使?的Exchange名稱(消息隊列主題名稱)
content-type: text/plain # application/json # 消息類型設(shè)置,?如json,自動將對象轉(zhuǎn)為json
binder: etpmsRabbitMQ # 關(guān)聯(lián)MQ服務(wù)
group: task
rabbit:
bindings:
my-input:
consumer:
bindingRoutingKey: task
input:
consumer:
bindingRoutingKey: register這里我就定義了兩個通道,一個是默認(rèn)的input,一個是自定的
package top.chenyt.consumer;
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
public interface MySink {
String MY_INPUT = "my-input";
@Input(MY_INPUT)
SubscribableChannel myinput();
}
package top.chenyt.consumer;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Service;
/**
* @ClassName etpms-parent
* @Author Jinondo
* @Date 2022/1/31 12:42
*/
@Service
public class ConsumerMsg {
@StreamListener(Sink.INPUT)
public void receiveMessages(Message<String> message) {
System.out.println("========= input接收到的消息:" + message.getPayload());
}
@StreamListener(MySink.MY_INPUT)
public void receiveMessages02(Message<String> message) {
System.out.println("========= myinput接收到的消息:" + message.getPayload());
}
}
package top.chenyt;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Sink;
import top.chenyt.consumer.MySink;
/**
* @ClassName etpms-parent
* @Author Jinondo
* @Date 2022/1/31 12:42
*/
@SpringBootApplication
@Slf4j
@EnableBinding({Sink.class, MySink.class})
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
這樣就能實現(xiàn)根據(jù)不同的消息類型對應(yīng)到不同的隊列且不同的路由key去了
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
java中創(chuàng)建寫入文件的6種方式詳解與源碼實例
這篇文章主要介紹了java中創(chuàng)建寫入文件的6種方式詳解與源碼實例,Files.newBufferedWriter(Java 8),Files.write(Java 7 推薦),PrintWriter,File.createNewFile,FileOutputStream.write(byte[] b) 管道流,需要的朋友可以參考下2022-12-12
java使用BeanUtils.copyProperties方法對象復(fù)制同名字段類型不同賦值為空問題解決方案
這篇文章主要給大家介紹了關(guān)于java使用BeanUtils.copyProperties方法對象復(fù)制同名字段類型不同賦值為空問題的解決方案,文中通過代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-11-11
MyBatis-Plus 中 的動態(tài)SQL 片段(sqlSegment)詳解
MyBatis-Plus的sqlSegment通過Wrapper動態(tài)生成SQL片段,支持XML中${ew.customSqlSegment}引用,結(jié)合Lambda表達(dá)式避免硬編碼,適用于動態(tài)查詢、邏輯刪除等場景,提升代碼可維護性與靈活性,本文給大家介紹MyBatis-Plus中的動態(tài)SQL片段(sqlSegment)講解,感興趣的朋友一起看看吧2025-06-06

