Commit 1b15fb384547411fe7d0d7c180e8553ff75d2a02
1 parent
53697b55
【代码优化】IoT: 优化数据桥接缓存实现
Showing
2 changed files
with
88 additions
and
41 deletions
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 | 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 | 3 | import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum; |
| 5 | 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 | 6 | import lombok.extern.slf4j.Slf4j; |
| 10 | 7 | import org.apache.rocketmq.client.producer.DefaultMQProducer; |
| 11 | 8 | import org.apache.rocketmq.client.producer.SendResult; |
| ... | ... | @@ -14,9 +11,7 @@ import org.apache.rocketmq.common.message.Message; |
| 14 | 11 | import org.apache.rocketmq.remoting.common.RemotingHelper; |
| 15 | 12 | import org.springframework.stereotype.Component; |
| 16 | 13 | |
| 17 | -import java.time.Duration; | |
| 18 | 14 | import java.time.LocalDateTime; |
| 19 | -import java.util.concurrent.Executors; | |
| 20 | 15 | |
| 21 | 16 | /** |
| 22 | 17 | * RocketMQ 的 {@link IotDataBridgeExecute} 实现类 |
| ... | ... | @@ -25,41 +20,7 @@ import java.util.concurrent.Executors; |
| 25 | 20 | */ |
| 26 | 21 | @Component |
| 27 | 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 | 25 | @Override |
| 65 | 26 | public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) { |
| ... | ... | @@ -74,7 +35,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute { |
| 74 | 35 | private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) { |
| 75 | 36 | try { |
| 76 | 37 | // 1. 获取或创建 Producer |
| 77 | - DefaultMQProducer producer = PRODUCER_CACHE.get(config); | |
| 38 | + DefaultMQProducer producer = (DefaultMQProducer) getProducer(config); | |
| 78 | 39 | |
| 79 | 40 | // 2.1 创建消息对象,指定Topic、Tag和消息体 |
| 80 | 41 | Message msg = new Message( |
| ... | ... | @@ -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 | 75 | // TODO @芋艿:测试代码,后续清理 |
| 99 | 76 | public static void main(String[] args) { |
| 100 | 77 | // 1. 创建一个共享的实例 | ... | ... |