Springboot使用redisson?+?自定義注解實(shí)現(xiàn)消息的發(fā)布訂閱(解決方案)
前言
在一些小型場(chǎng)景下,使用mq中間件可能會(huì)為原有項(xiàng)目增加不少維護(hù)成本,使用redisson實(shí)現(xiàn)消息的收發(fā)是個(gè)不錯(cuò)的選擇
什么是redisson?
官網(wǎng):Redisson: Easy Redis Java client with features of In-Memory Data Grid
Redisson是一個(gè)基于Redis的Java駐留內(nèi)存數(shù)據(jù)網(wǎng)格(In-Memory Data Grid)和分布式鎖框架。它提供了一系列的分布式Java對(duì)象和服務(wù),可以幫助開發(fā)者更方便地使用Redis作為數(shù)據(jù)存儲(chǔ)和分布式鎖的解決方案。
Redisson的主要功能包括:
- 分布式集合:Redisson提供了分布式的Set、List、Queue、Deque等集合,可以在分布式環(huán)境下進(jìn)行操作,實(shí)現(xiàn)數(shù)據(jù)共享和協(xié)作。
- 分布式映射:Redisson提供了分布式的Map、Multimap、ConcurrentMap等映射結(jié)構(gòu),可以在分布式環(huán)境下進(jìn)行操作,實(shí)現(xiàn)數(shù)據(jù)的存儲(chǔ)和共享。
- 分布式鎖:Redisson提供了可重入鎖、公平鎖、讀寫鎖等分布式鎖,可以在分布式環(huán)境下實(shí)現(xiàn)資源的互斥訪問(wèn),保證數(shù)據(jù)的一致性和并發(fā)安全。
- 分布式對(duì)象:Redisson提供了分布式的AtomicLong、CountDownLatch、Semaphore等對(duì)象,可以在分布式環(huán)境下實(shí)現(xiàn)共享狀態(tài)和協(xié)作操作。
Redisson的使用場(chǎng)景包括但不限于:
分布式緩存:Redisson可以作為分布式緩存的解決方案,將數(shù)據(jù)存儲(chǔ)在Redis中,提高數(shù)據(jù)的讀取速度和系統(tǒng)的性能。
分布式鎖:Redisson可以用于實(shí)現(xiàn)分布式鎖,保證在分布式環(huán)境下對(duì)共享資源的互斥訪問(wèn),避免數(shù)據(jù)的并發(fā)沖突。
分布式任務(wù)調(diào)度:Redisson可以用于實(shí)現(xiàn)分布式任務(wù)調(diào)度,將任務(wù)分發(fā)到不同的節(jié)點(diǎn)上執(zhí)行,提高系統(tǒng)的并發(fā)處理能力。
Redisson的優(yōu)點(diǎn)包括:
簡(jiǎn)單易用:Redisson提供了簡(jiǎn)潔的API和豐富的文檔,使得使用者可以快速上手。
高性能:Redisson利用Redis的高性能特性,可以實(shí)現(xiàn)快速的數(shù)據(jù)讀寫和并發(fā)操作。
可靠性:Redisson提供了分布式鎖和數(shù)據(jù)持久化等機(jī)制,保證數(shù)據(jù)的一致性和可靠性。
Redisson的缺點(diǎn)包括:
依賴于Redis:Redisson需要依賴Redis作為數(shù)據(jù)存儲(chǔ)和分布式鎖的后端,需要確保Redis的可用性和性能。
部署復(fù)雜性:Redisson的部署和配置相對(duì)復(fù)雜,需要對(duì)Redis和Redisson的相關(guān)參數(shù)進(jìn)行調(diào)優(yōu)和配置。
redisson發(fā)布訂閱的基本使用
// 創(chuàng)建Redisson客戶端 RedissonClient redisson = Redisson.create(); // 獲取RTopic對(duì)象 RTopic<String> topic = redisson.getTopic("myTopic"); // 發(fā)布消息 topic.publish("Hello, Redisson!"); // 添加監(jiān)聽器 topic.addListener(String.class, (channel, msg) -> { System.out.println("Received message: " + msg); }); // 關(guān)閉Redisson客戶端 redisson.shutdown();
發(fā)布和訂閱,是我們需要對(duì)同一個(gè) Topic 進(jìn)行發(fā)布和監(jiān)聽操作。但這個(gè)操作的代碼是一種手動(dòng)編碼,但在我們實(shí)際使用中,如果所有的都是手動(dòng)編碼,一個(gè)是非常麻煩,再有一個(gè)是非常累人。通過(guò)自定義注解,來(lái)完成動(dòng)態(tài)監(jiān)聽和將對(duì)象動(dòng)態(tài)注入到 Spring 容器中,讓需要注入的屬性,可以被動(dòng)態(tài)注入。
結(jié)合自定義注解優(yōu)雅實(shí)現(xiàn)
導(dǎo)入依賴
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.14.1</version> </dependency>
編寫redisson初始化配置
redis: sdk: config: host: localhost port: 6379 pool-size: 10 min-idle-size: 5 idle-timeout: 30000 connect-timeout: 5000 retry-attempts: 3 retry-interval: 1000 ping-interval: 60000 keep-alive: true
編寫redisson配置類
/** * @description redis連接配置 * @create 2023/12/17 20:48:13 */ @Data @ConfigurationProperties(prefix = "redis.sdk.config", ignoreInvalidFields = true) public class RedissonCientConfigProperties { /** host:ip */ private String host; /** 端口 */ private int port; /** 賬密 */ private String password; /** 設(shè)置連接池的大小,默認(rèn)為64 */ private int poolSize = 64; /** 設(shè)置連接池的最小空閑連接數(shù),默認(rèn)為10 */ private int minIdleSize = 10; /** 設(shè)置連接的最大空閑時(shí)間(單位:毫秒),超過(guò)該時(shí)間的空閑連接將被關(guān)閉,默認(rèn)為10000 */ private int idleTimeout = 10000; /** 設(shè)置連接超時(shí)時(shí)間(單位:毫秒),默認(rèn)為10000 */ private int connectTimeout = 10000; /** 設(shè)置連接重試次數(shù),默認(rèn)為3 */ private int retryAttempts = 3; /** 設(shè)置連接重試的間隔時(shí)間(單位:毫秒),默認(rèn)為1000 */ private int retryInterval = 1000; /** 設(shè)置定期檢查連接是否可用的時(shí)間間隔(單位:毫秒),默認(rèn)為0,表示不進(jìn)行定期檢查 */ private int pingInterval = 0; /** 設(shè)置是否保持長(zhǎng)連接,默認(rèn)為true */ private boolean keepAlive = true; }
編寫自定義主題注解,用來(lái)指定主題
/** * @description redisson 消息主題注解 * @create 2023/12/17 21:56:10 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented public @interface RedisTopic { // 主題名稱 String topic() default ""; }
初始化Redisson客戶端,注冊(cè)主題監(jiān)聽
/** * @description redis客戶端 * @create 2023/12/17 20:49:41 */ @Configuration @EnableConfigurationProperties(RedisCientConfigProperties.class) public class RedisClientConfig { public RedissonClient redissonClient(ConfigurableApplicationContext applicationContext, RedisCientConfigProperties properties) { Config config = new Config(); config.useSingleServer() .setAddress("redis://" + properties.getHost() + ":" + properties.getPort()) .setPassword(properties.getPassword()) .setConnectionPoolSize(properties.getPoolSize()) .setConnectionMinimumIdleSize(properties.getMinIdleSize()) .setIdleConnectionTimeout(properties.getIdleTimeout()) .setConnectTimeout(properties.getConnectTimeout()) .setRetryAttempts(properties.getRetryAttempts()) .setRetryInterval(properties.getRetryInterval()) .setPingConnectionInterval(properties.getPingInterval()) .setKeepAlive(properties.isKeepAlive()) ; RedissonClient redissonClient = Redisson.create(config); // 注冊(cè)消息發(fā)布訂閱主題Topic // 找到所有實(shí)現(xiàn)了Redisson中MessageListener接口的bean名字 String[] beanNamesForType = applicationContext.getBeanNamesForType(MessageListener.class); for (String beanName : beanNamesForType) { // 通過(guò)bean名字獲取到監(jiān)聽bean MessageListener bean = applicationContext.getBean(beanName, MessageListener.class); Class<? extends MessageListener> beanClass = bean.getClass(); // 如果bean的注解里包含我們的自定義注解RedisTopic.class,則以RedisTopic注解的值作為name將該bean注冊(cè)到bean工廠,方便在別處注入 if (beanClass.isAnnotationPresent(RedisTopic.class)) { RedisTopic redisTopic = beanClass.getAnnotation(RedisTopic.class); RTopic topic = redissonClient.getTopic(redisTopic.topic()); topic.addListener(String.class, bean); ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); beanFactory.registerSingleton(redisTopic.topic(), topic); } } return redissonClient; } }
在監(jiān)聽器上聲明注解,如下服務(wù)即訂閱了testRedisTopic02主題
@Slf4j @Service @RedisTopic(topic = "testRedisTopic02") public class RedisTopicListener02 implements MessageListener<String> { @Override public void onMessage(CharSequence channel, String msg) { log.info("02-監(jiān)聽消息(Redis 發(fā)布/訂閱): {}", msg); } }
使用,發(fā)布消息
@Slf4j @Repository public class OrderRepository implements IOrderRepository { @Resource(name = "testRedisTopic02") private RTopic testRedisTopic02; @Resource(name = "testRedisTopic03") private RTopic testRedisTopic03; @Override public String createOrder(OrderAggregate orderAggregate) { // 向 testRedisTopic02 發(fā)布消息 testRedisTopic02.publish(JSON.toJSONString(orderEntity)); // 向 testRedisTopic03 發(fā)布消息 testRedisTopic03.publish(JSON.toJSONString(orderEntity)); return orderId; } }
到此這篇關(guān)于Springboot中使用redisson + 自定義注解優(yōu)雅的實(shí)現(xiàn)消息的發(fā)布訂閱的文章就介紹到這了,更多相關(guān)Springboot中使用redisson + 自定義注解優(yōu)雅的實(shí)現(xiàn)消息的發(fā)布訂閱內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot 1.5.2 集成kafka的簡(jiǎn)單例子
本篇文章主要介紹了springboot 1.5.2 集成kafka的簡(jiǎn)單例子 ,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11SpringBoot多文件分布式上傳功能實(shí)現(xiàn)
本文詳細(xì)介紹了如何在SpringBoot中實(shí)現(xiàn)多文件分布式上傳,并用代碼給出了相應(yīng)的實(shí)現(xiàn)思路和實(shí)現(xiàn)步驟,感興趣的朋友跟隨小編一起看看吧2023-06-06mybatis中<if>標(biāo)簽bool值類型為false判斷方法
這篇文章主要給大家介紹了關(guān)于mybatis中<if>標(biāo)簽bool值類型為false判斷方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用mybatis具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08maven項(xiàng)目錯(cuò)誤:找不到或無(wú)法加載主類?XXX問(wèn)題
這篇文章主要介紹了maven項(xiàng)目錯(cuò)誤:找不到或無(wú)法加載主類?XXX問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02Easyui的combobox實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)級(jí)聯(lián)效果
這篇文章主要介紹了Easyui的combobox實(shí)現(xiàn)動(dòng)態(tài)數(shù)據(jù)級(jí)聯(lián)效果的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-06-06Java開發(fā)學(xué)習(xí) Java數(shù)組操作工具
這篇文章主要為大家詳細(xì)介紹了自己編寫的Java數(shù)組操作工具,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04