Spring項(xiàng)目集成RabbitMQ及自動(dòng)創(chuàng)建隊(duì)列
簡(jiǎn)單記錄Spring項(xiàng)目集成RabbitMQ的過程,重點(diǎn)記錄生產(chǎn)者項(xiàng)目自動(dòng)創(chuàng)建隊(duì)列的操作,因該問題給項(xiàng)目帶來很多麻煩。
本文內(nèi)容分別在Spring(V5.2.6)和Spring Boot(V2.5.14)兩個(gè)項(xiàng)目中經(jīng)過了驗(yàn)證,下述示例代碼來自于SpringBoot項(xiàng)目,遷移到Spring項(xiàng)目中需稍微調(diào)整。
一、Spring Boot集成RabbitMQ
1. 在Maven中加入依賴
Spring項(xiàng)目和SpringBoot項(xiàng)目的依賴有區(qū)別,按需引入:
<!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework.amqp</groupId> <artifactId>spring-rabbit</artifactId> <version>2.2.9.RELEASE</version> </dependency>
2. 在Spring配置文件增加配置項(xiàng)
spring: rabbitmq: # 基礎(chǔ)項(xiàng) host: 192.168.1.123 port: 5672 username: admin password: admin # virtualhost需要提前在MQ的Web管理界面里手動(dòng)創(chuàng)建,或者配置默認(rèn)host"/" virtual-host: /test # 生產(chǎn)者 #確認(rèn)消息已發(fā)送到交換機(jī)(Exchange) publisher-confirm-type: correlated #確認(rèn)消息已發(fā)送到隊(duì)列(Queue) publisher-returns: true # 消費(fèi)者 listener: type: simple simple: default-requeue-rejected: false acknowledge-mode: auto #確認(rèn)模式 prefetch: 1 #限制每次發(fā)送一條數(shù)據(jù) max-concurrency: 1 #啟動(dòng)消費(fèi)者最大數(shù)量 concurrency: 1 #同一個(gè)隊(duì)列啟動(dòng)幾個(gè)消費(fèi)者 retry: enabled: true #是否支持重試
說明:這里僅按照現(xiàn)有項(xiàng)目的配置列出,在實(shí)際的項(xiàng)目中,還是需要根據(jù)自身實(shí)際情況做出調(diào)整。
3. 編寫生產(chǎn)者代碼
3.1 創(chuàng)建RabbitMQ配置類:
@Configuration public class RabbitMQConfig { //queue public static final String WORK_QUEUE = "test.queue"; //exchange public static final String WORK_DIRECTEXCHANGE = "test.directExchange"; //routing public static final String WORK_DIRECTROUTING = "test.directRouting"; @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); return rabbitTemplate; } // Queue @Bean public Queue directQueue() { Map<String, Object> argsMap = new HashMap<String, Object>(); argsMap.put("x-max-priority", 5); Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap); return queue; } //Direct交換機(jī) @Bean DirectExchange directExchange() { return new DirectExchange(WORK_DIRECTEXCHANGE, true, false); } //綁定 @Bean Binding bindingDirect() { return BindingBuilder.bind(directQueue()).to(directExchange()).with(WORK_DIRECTROUTING); } }
3.2 編寫發(fā)送消息工具類:
@Component public class RabbitMQUtils { private static RabbitTemplate rabbitTemplate; @Autowired public RabbitMQUtils(RabbitTemplate rabbitTemplate) { this.rabbitTemplate = rabbitTemplate; } public static void sendMsg(String msg) throws AmqpException { try { rabbitTemplate.convertAndSend(RabbitMQConfig.WORK_DIRECTEXCHANGE, RabbitMQConfig.WORK_DIRECTROUTING, msg); } catch (AmqpException e) { throw new AmqpException ("RabbitMQ發(fā)送消息異常", e); } } }
3.3 編寫單元測(cè)試,測(cè)試發(fā)送消息結(jié)果。
4. 編寫消費(fèi)者代碼
4.1 編寫監(jiān)聽器:
@Component public class RabbitMQListener { @RabbitListener(queues = {Constants.WORK_QUEUE})//監(jiān)聽隊(duì)列 public void listener(String msg, Message message) { System.out.println(msg); System.out.println(message.getBody()); } }
二、存在的問題
1. 問題描述
實(shí)際項(xiàng)目中,消息的生產(chǎn)者和消費(fèi)者不在同一項(xiàng)目中,如果先啟動(dòng)消費(fèi)者會(huì)因?yàn)闆]有隊(duì)列而啟動(dòng)失敗。
2. 嘗試解決
2.1 方式一:最容易想到的是,在MQ的Web管理界面中手動(dòng)創(chuàng)建隊(duì)列:
- 該方式在實(shí)際操作是個(gè)不容易的事情,因?yàn)檫€要?jiǎng)?chuàng)建Channel和Exchange,何況發(fā)布的人不一定是開發(fā)的人,溝通繁瑣,極易出錯(cuò),好像程序還是半成品似的;
2.2 方式二:?jiǎn)?dòng)消費(fèi)者項(xiàng)目時(shí),監(jiān)聽器發(fā)現(xiàn)不存在隊(duì)列自動(dòng)創(chuàng)建:
- “通過@RabbitListener”的參數(shù),確實(shí)可以實(shí)現(xiàn);
- 但是這種方式在我的項(xiàng)目中出現(xiàn)了新問題,消費(fèi)者項(xiàng)目啟動(dòng)后創(chuàng)建了隊(duì)列,但是生產(chǎn)者發(fā)送消息出錯(cuò),貌似沒有了權(quán)限?
- 當(dāng)時(shí)因?yàn)轫?xiàng)目工期,并未深究,具體錯(cuò)誤也沒記錄下來;應(yīng)該是自己的代碼有問題;
- 因此,不能確認(rèn)該方式的可行性,或者具體實(shí)現(xiàn)方式。
2.3 方式三:先啟動(dòng)生產(chǎn)者項(xiàng)目:
- 因RabbitMQ懶加載模式,所以單純啟動(dòng)項(xiàng)目是不會(huì)創(chuàng)建隊(duì)列的;
- 因此,最開始的想法是,啟動(dòng)項(xiàng)目后,先發(fā)送一條測(cè)試消息去創(chuàng)建隊(duì)列,項(xiàng)目確實(shí)用該方式使用了一段時(shí)間;
- 近期在升級(jí)項(xiàng)目時(shí),發(fā)現(xiàn)個(gè)現(xiàn)象,沒有隊(duì)列時(shí)候的第一條消息確實(shí)可以創(chuàng)建隊(duì)列,但是MQ里沒有消息,是空隊(duì)列;
- 種種問題促使自己重新尋找解決方式,在生產(chǎn)者項(xiàng)目啟動(dòng)后可以自動(dòng)創(chuàng)建隊(duì)列,因此有了本篇文章;
- 很慚愧,其實(shí)答案一直在,但是自己對(duì)MQ的認(rèn)知一直停留在簡(jiǎn)單使用里,希望有機(jī)會(huì)能深入的學(xué)習(xí)一下吧。
三、生產(chǎn)者項(xiàng)目創(chuàng)建隊(duì)列
1. 在RabbitMQ配置類中加入RabbitAdmin
@Bean public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) { RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); rabbitAdmin.setAutoStartup(true); return rabbitAdmin; }
2. 通過RabbitAdmin聲明隊(duì)列,完成隊(duì)列的創(chuàng)建
@Bean public Queue directQueue() { Map<String, Object> argsMap = new HashMap<String, Object>(); argsMap.put("x-max-priority", 5); Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap); // 聲明隊(duì)列 rabbitAdmin.declareQueue(queue); return queue; }
3. 修改后的完整配置類
@Configuration public class RabbitMQConfig { //queue public static final String WORK_QUEUE = "test.queue"; //exchange public static final String WORK_DIRECTEXCHANGE = "test.directExchange"; //routing public static final String WORK_DIRECTROUTING = "test.directRouting"; @Autowired private RabbitAdmin rabbitAdmin; @Bean public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) { RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory); return rabbitTemplate; } @Bean public RabbitAdmin rabbitAdmin(ConnectionFactory connectionFactory) { RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory); rabbitAdmin.setAutoStartup(true); return rabbitAdmin; } @Bean public Queue directQueue() { Map<String, Object> argsMap = new HashMap<String, Object>(); argsMap.put("x-max-priority", 5); Queue queue = new Queue(WORK_QUEUE, true, false, false, argsMap); rabbitAdmin.declareQueue(queue); return queue; } //Direct交換機(jī) @Bean DirectExchange directExchange() { return new DirectExchange(WORK_DIRECTEXCHANGE, true, false); } //綁定 @Bean Binding bindingDirect() { return BindingBuilder.bind(directQueue()).to(directExchange()).with(WORK_DIRECTROUTING); } }
4. 啟動(dòng)項(xiàng)目,查看隊(duì)列創(chuàng)建情況
經(jīng)過多次測(cè)試,在僅手動(dòng)創(chuàng)建virtual-host的前提下,啟動(dòng)項(xiàng)目,隊(duì)列可以自動(dòng)創(chuàng)建,且發(fā)送/接收消息都正常完成。
到此這篇關(guān)于Spring項(xiàng)目集成RabbitMQ及自動(dòng)創(chuàng)建隊(duì)列的文章就介紹到這了,更多相關(guān)Spring RabbitMQ自動(dòng)創(chuàng)建隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot使用RabbitMQ延時(shí)隊(duì)列(小白必備)
- SpringBoot集成RabbitMQ的方法(死信隊(duì)列)
- springboot實(shí)現(xiàn)rabbitmq的隊(duì)列初始化和綁定
- Spring Boot與RabbitMQ結(jié)合實(shí)現(xiàn)延遲隊(duì)列的示例
- 消息隊(duì)列 RabbitMQ 與 Spring 整合使用的實(shí)例代碼
- rabbitmq結(jié)合spring實(shí)現(xiàn)消息隊(duì)列優(yōu)先級(jí)的方法
- Spring學(xué)習(xí)筆記3之消息隊(duì)列(rabbitmq)發(fā)送郵件功能
相關(guān)文章
JDK源碼分析之String、StringBuilder和StringBuffer
這篇文章主要給大家介紹了關(guān)于JDK源碼分析之String、StringBuilder和StringBuffer的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用jdk具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-05-05解決@DateTimeFormat格式化時(shí)間出錯(cuò)問題
這篇文章主要介紹了解決@DateTimeFormat格式化時(shí)間出錯(cuò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12java 中動(dòng)態(tài)代理(JDK,cglib)實(shí)例代碼
這篇文章主要介紹了java 中動(dòng)態(tài)代理,這里介紹了JDK 動(dòng)態(tài)代理與 cglib 動(dòng)態(tài)代理的相關(guān)資料2017-04-04Java回調(diào)函數(shù)實(shí)例代碼詳解
這篇文章主要介紹了Java回調(diào)函數(shù)實(shí)例代碼詳解,需要的朋友可以參考下2017-10-10SpringBoot?整合mapstruct的實(shí)現(xiàn)步驟
這篇文章主要介紹了SpringBoot整合mapstruct,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-11-11Vue實(shí)現(xiàn)驗(yàn)證碼登錄的超詳細(xì)步驟
這篇文章主要給大家介紹了關(guān)于Vue實(shí)現(xiàn)驗(yàn)證碼登錄的超詳細(xì)步驟,我們?cè)谑褂胿ue進(jìn)行前端開發(fā)時(shí)都需要登錄驗(yàn)證,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09實(shí)例解析Java設(shè)計(jì)模式編程中的適配器模式使用
本篇文章主要通過實(shí)例對(duì)適配器模式進(jìn)行了詳解,需要的朋友可以參考下2017-04-04關(guān)于Scanner中nextInt()、nextLine()等方法總結(jié)與問題解決
這篇文章主要介紹了關(guān)于Scanner中nextInt()、nextLine()等方法總結(jié)與問題解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。2022-11-11