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