這兩天在和一小伙伴研究解決RabbitMQ集群重啟慢導致Consumer自動重連超時的問題,已經有了解決方案,接下來需要做個整理,由于同時涉及到springboot自動配置、springboot-amqp、spring-rabbit等諸多技術,先往后拖一下,

本文說什么呢?通過一個程式案例來聊聊程式里隨處可見的interface,
先來個四連問:什么情況下定義interface?為什么要定義interface?定義interface是為了什么?你用對interface了嗎?
接下來看這個案例吧,
程式里使用了RabbitMQ,下面 MQSender 是個interface,定義了生產者往mq放訊息的兩種方式:
package com.yft.rabbitmq.service; import com.yft.rabbitmq.constant.BindingEnum; /** * 延遲發送服務類 * * @author liuhongjie [email protected] * @date 2022年06月12日 */ public interface MQSender { /** * 發送訊息 * * @param bindingEnum 宣告binding的enum * @param msg 推送的訊息 * @param delaySeconds 延遲的時間,秒 */ void sendDelayMsg(BindingEnum bindingEnum, Object msg, int delaySeconds); /** * 發送訊息 * * @param bindingEnum 宣告binding的enum * @param msg 推送的訊息 */ void sendMsg(BindingEnum bindingEnum, Object msg); }
其中 BindingEnum 是個列舉,封裝定義了exchange和queue及兩者的binding關系
package com.yft.rabbitmq.constant; public enum BindingEnum { SYNC_REVIEW_RECORD("sync-review-record", "sync-review-record", "sync-review-record"), PAY_SETTLE("pay-settle","pay-settle","pay-settle"), PAY_SETTLE_QUERY_DELAY("pay-settle-query-delay", "pay-settle-query-delay", "pay-settle-query-delay"), ; String exchangeName; String queueName; String routingKey; private static final String EXCHANGE_NAME_PREFIX = "exchange.levy-platform."; private static final String QUEUE_NAME_PREFIX = "queue.levy-platform."; private static final String ROUTING_KEY_PREFIX = "bindingKey.levy-platform."; BindingEnum(String exchangeName, String queueName, String routingKey) { this.exchangeName = exchangeName; this.queueName = queueName; this.routingKey = routingKey; } public String getExchangeName() { return EXCHANGE_NAME_PREFIX + exchangeName; } public String getQueueName() { return QUEUE_NAME_PREFIX + queueName; } public String getRoutingKey() { return ROUTING_KEY_PREFIX + routingKey; } }View Code
MQSender只有一個實作類 DefaultMQSender ,我們同樣貼出來它的代碼
package com.yft.rabbitmq.service; import com.yft.rabbitmq.constant.BindingEnum; import lombok.RequiredArgsConstructor; import org.springframework.amqp.core.AmqpTemplate; /** * 延遲發送的默認實作 * * @author liuhongjie [email protected] * @date 2022年06月12日 */ @RequiredArgsConstructor public class DefaultMQSender implements MQSender { private final AmqpTemplate amqpTemplate; @Override public void sendDelayMsg(BindingEnum bindingEnum, Object msg, int delaySeconds) { amqpTemplate.convertAndSend(bindingEnum.getExchangeName(), bindingEnum.getRoutingKey(), msg, message -> { message.getMessageProperties().setDelay(delaySeconds * 1000); return message; }); } @Override public void sendMsg(BindingEnum bindingEnum, Object msg) { amqpTemplate.convertAndSend(bindingEnum.getExchangeName(), bindingEnum.getRoutingKey(), msg); } }View Code
使用的話,見下面的 MQSenderConfig,它定義了相關的bean
package com.cn.yft.config; import com.yft.rabbitmq.service.DefaultMQSender; import com.yft.rabbitmq.service.MQSender; import org.springframework.amqp.core.AmqpTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Author wjx * @Date 2022/7/6 */ @Configuration public class MQSenderConfig { @Autowired private AmqpTemplate rabbitTemplate; @Bean public MQSender mqSender() { return new DefaultMQSender(rabbitTemplate); } }View Code
案例介紹完畢,

那么,MQSender 這個interface的作用是什么?
當事人回答:作用是我能很方便的看到這個介面的能力,
當事人回答:如果以后不用RabbitMQ,新的訊息中間件直接實作這個interface就行了,
如此幾次對答后,幾分鐘后,小伙子開始覺得這個interface好像意義并不明顯,
以這個程式實作場景來看,去掉這個interface是可以的,反而還會增強程式易讀性,
那么,以這個場景來說,怎么定義一個合理的interface呢?
我畫了下面的草圖,圖樣圖森破,可愛的小伙立即提出了新的疑惑,我當然明白他的疑惑,秉承我的風格,我并沒有繼續闡開,而是讓這小伙后續琢磨琢磨,


好,在這里,我揭曉我的想法,
MQSender 搖身一變成:
package com.yft.rabbitmq.service; import com.yft.dto.MQMsgModel; /** * 延遲發送服務類 */ public interface MQSender { /** * 發送訊息 * @param mqMsg mq訊息物件 */ void sendMsg(MQMsgModel mqMsg); }
它的兩個實作類:DefaultMQSender 是實時發送訊息,DelayMQSender 是延遲發送訊息
package com.yft.rabbitmq.service; /** * 即時發送訊息的實作 */ @RequiredArgsConstructor public class DefaultMQSender implements MQSender { private final AmqpTemplate amqpTemplate; @Override public void sendMsg(MQMsgModel mqMsgModel) { BindingEnum bindingEnum = mqMsgModel.getBindingEnum(); amqpTemplate.convertAndSend(bindingEnum.getExchangeName(), bindingEnum.getRoutingKey(), mqMsgModel.getMsg()); } }
|
package com.yft.rabbitmq.service; /** * 延遲發送訊息的實作 */ @RequiredArgsConstructor public class DelayMQSender implements MQSender { private final AmqpTemplate amqpTemplate; @Override public void sendMsg(MQMsgModel mqMsgModel) { BindingEnum bindingEnum = mqMsgModel.getBindingEnum(); amqpTemplate.convertAndSend(bindingEnum.getExchangeName(), bindingEnum.getRoutingKey(), mqMsgModel.getMsg(), message -> { message.getMessageProperties().setDelay(mqMsgModel.getDelaySeconds() * 1000); return message; }); } }
|
注意到多了一個 MQMsgModel, 好,我們來看這個 MQMsgModel,它是一個資料傳輸物件,定義了mq訊息的屬性
package com.yft.dto; import com.yft.rabbitmq.constant.BindingEnum; import lombok.Data; /** * mq訊息物件 */ @Data public class MQMsgModel{ private BindingEnum bindingEnum; private Object msg; /** * 指定訊息的延遲時間,單位:秒 →→→→(非延遲訊息,不用指定) */ private Integer delaySeconds; }
使用的話, MQSenderConfig 定義兩個bean就OK了
package com.cn.yft.config; @Configuration public class MQSenderConfig { @Autowired private AmqpTemplate rabbitTemplate; @Bean public MQSender mqSender() { return new DefaultMQSender(rabbitTemplate); } @Bean public MQSender delayMqSender() { return new DelayMQSender(rabbitTemplate); } }
(完畢)

再貼一下上面的四連問:什么情況下定義interface?為什么要定義interface?定義interface是為了什么?你用對interface了嗎?
不知你是否有了一些答案?
當看到一些不好的代碼時,會發現我還算優秀;當看到優秀的代碼時,也才意識到持續學習的重要!--buguge
本文來自博客園,轉載請注明原文鏈接:https://www.cnblogs.com/buguge/p/16526595.html
<style>hr.signhr{width:80%;margin:0 auto;border: 0;height: 4px;background-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0))}</style>
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/500493.html
標籤:Java
上一篇:并查集
