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 | \ 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. 创建一个共享的实例 |