Commit 1b15fb384547411fe7d0d7c180e8553ff75d2a02

Authored by puhui999
1 parent 53697b55

【代码优化】IoT: 优化数据桥接缓存实现

yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/AbstractCacheableDataBridgeExecute.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.service.rule.action.databridge;
  2 +
  3 +import com.google.common.cache.CacheBuilder;
  4 +import com.google.common.cache.CacheLoader;
  5 +import com.google.common.cache.LoadingCache;
  6 +import lombok.extern.slf4j.Slf4j;
  7 +
  8 +import java.time.Duration;
  9 +
  10 +/**
  11 + * 带缓存功能的数据桥接执行器抽象类
  12 + *
  13 + * @author HUIHUI
  14 + */
  15 +@Slf4j
  16 +public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute {
  17 +
  18 + /**
  19 + * Producer 缓存
  20 + */
  21 + private final LoadingCache<Object, Object> PRODUCER_CACHE = CacheBuilder.newBuilder()
  22 + .expireAfterAccess(Duration.ofMinutes(30))
  23 + .removalListener(notification -> {
  24 + Object producer = notification.getValue();
  25 + if (producer == null) {
  26 + return;
  27 + }
  28 + try {
  29 + closeProducer(producer);
  30 + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey());
  31 + } catch (Exception e) {
  32 + log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e);
  33 + }
  34 + })
  35 + .build(new CacheLoader<Object, Object>() {
  36 + @Override
  37 + public Object load(Object config) throws Exception {
  38 + Object producer = initProducer(config);
  39 + log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config);
  40 + return producer;
  41 + }
  42 + });
  43 +
  44 + /**
  45 + * 获取生产者
  46 + *
  47 + * @param config 配置信息
  48 + * @return 生产者对象
  49 + */
  50 + protected Object getProducer(Object config) throws Exception {
  51 + return PRODUCER_CACHE.get(config);
  52 + }
  53 +
  54 + /**
  55 + * 初始化生产者
  56 + *
  57 + * @param config 配置信息
  58 + * @return 生产者对象
  59 + * @throws Exception 如果初始化失败
  60 + */
  61 + protected abstract Object initProducer(Object config) throws Exception;
  62 +
  63 + /**
  64 + * 关闭生产者
  65 + *
  66 + * @param producer 生产者对象
  67 + */
  68 + protected abstract void closeProducer(Object producer);
  69 +
  70 +}
0 \ No newline at end of file 71 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/action/databridge/IotRocketMQDataBridgeExecute.java
@@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge; @@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge;
3 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; 3 import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
4 import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; 4 import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
5 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage; 5 import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
6 -import com.google.common.cache.CacheBuilder;  
7 -import com.google.common.cache.CacheLoader;  
8 -import com.google.common.cache.LoadingCache;  
9 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
10 import org.apache.rocketmq.client.producer.DefaultMQProducer; 7 import org.apache.rocketmq.client.producer.DefaultMQProducer;
11 import org.apache.rocketmq.client.producer.SendResult; 8 import org.apache.rocketmq.client.producer.SendResult;
@@ -14,9 +11,7 @@ import org.apache.rocketmq.common.message.Message; @@ -14,9 +11,7 @@ import org.apache.rocketmq.common.message.Message;
14 import org.apache.rocketmq.remoting.common.RemotingHelper; 11 import org.apache.rocketmq.remoting.common.RemotingHelper;
15 import org.springframework.stereotype.Component; 12 import org.springframework.stereotype.Component;
16 13
17 -import java.time.Duration;  
18 import java.time.LocalDateTime; 14 import java.time.LocalDateTime;
19 -import java.util.concurrent.Executors;  
20 15
21 /** 16 /**
22 * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 17 * RocketMQ 的 {@link IotDataBridgeExecute} 实现类
@@ -25,41 +20,7 @@ import java.util.concurrent.Executors; @@ -25,41 +20,7 @@ import java.util.concurrent.Executors;
25 */ 20 */
26 @Component 21 @Component
27 @Slf4j 22 @Slf4j
28 -public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {  
29 -  
30 - /**  
31 - * 针对 {@link IotDataBridgeDO.RocketMQConfig} 的 DefaultMQProducer 缓存  
32 - */  
33 - // TODO @puhui999:因为 kafka 之类也存在这个情况,是不是得搞个抽象类。提供一个 initProducer,和 closeProducer 方法  
34 - private final LoadingCache<IotDataBridgeDO.RocketMQConfig, DefaultMQProducer> PRODUCER_CACHE = CacheBuilder.newBuilder()  
35 - .refreshAfterWrite(Duration.ofMinutes(10)) // TODO puhui999:应该是 read 30 分钟哈  
36 - // 增加移除监听器,自动关闭 producer  
37 - .removalListener(notification -> {  
38 - DefaultMQProducer producer = (DefaultMQProducer) notification.getValue();  
39 - // TODO puhui999:if return,更简短哈  
40 - if (producer != null) {  
41 - try {  
42 - producer.shutdown();  
43 - log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey());  
44 - } catch (Exception e) {  
45 - log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e);  
46 - }  
47 - }  
48 - })  
49 - // TODO @puhui999:就同步哈,不用异步处理。  
50 - // 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程  
51 - .build(CacheLoader.asyncReloading(new CacheLoader<IotDataBridgeDO.RocketMQConfig, DefaultMQProducer>() {  
52 -  
53 - @Override  
54 - public DefaultMQProducer load(IotDataBridgeDO.RocketMQConfig config) throws Exception {  
55 - DefaultMQProducer producer = new DefaultMQProducer(config.getGroup());  
56 - producer.setNamesrvAddr(config.getNameServer());  
57 - producer.start();  
58 - log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config);  
59 - return producer;  
60 - }  
61 -  
62 - }, Executors.newCachedThreadPool())); 23 +public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute {
63 24
64 @Override 25 @Override
65 public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { 26 public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) {
@@ -74,7 +35,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { @@ -74,7 +35,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {
74 private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { 35 private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) {
75 try { 36 try {
76 // 1. 获取或创建 Producer 37 // 1. 获取或创建 Producer
77 - DefaultMQProducer producer = PRODUCER_CACHE.get(config); 38 + DefaultMQProducer producer = (DefaultMQProducer) getProducer(config);
78 39
79 // 2.1 创建消息对象,指定Topic、Tag和消息体 40 // 2.1 创建消息对象,指定Topic、Tag和消息体
80 Message msg = new Message( 41 Message msg = new Message(
@@ -95,6 +56,22 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { @@ -95,6 +56,22 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {
95 } 56 }
96 } 57 }
97 58
  59 + @Override
  60 + protected Object initProducer(Object config) throws Exception {
  61 + IotDataBridgeDO.RocketMQConfig rocketMQConfig = (IotDataBridgeDO.RocketMQConfig) config;
  62 + DefaultMQProducer producer = new DefaultMQProducer(rocketMQConfig.getGroup());
  63 + producer.setNamesrvAddr(rocketMQConfig.getNameServer());
  64 + producer.start();
  65 + return producer;
  66 + }
  67 +
  68 + @Override
  69 + protected void closeProducer(Object producer) {
  70 + if (producer instanceof DefaultMQProducer) {
  71 + ((DefaultMQProducer) producer).shutdown();
  72 + }
  73 + }
  74 +
98 // TODO @芋艿:测试代码,后续清理 75 // TODO @芋艿:测试代码,后续清理
99 public static void main(String[] args) { 76 public static void main(String[] args) {
100 // 1. 创建一个共享的实例 77 // 1. 创建一个共享的实例