【代码优化】IoT: 优化数据桥接缓存实现
This commit is contained in:
parent
53697b55c2
commit
1b15fb3845
|
@ -0,0 +1,70 @@
|
||||||
|
package cn.iocoder.yudao.module.iot.service.rule.action.databridge;
|
||||||
|
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.google.common.cache.LoadingCache;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 带缓存功能的数据桥接执行器抽象类
|
||||||
|
*
|
||||||
|
* @author HUIHUI
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractCacheableDataBridgeExecute implements IotDataBridgeExecute {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Producer 缓存
|
||||||
|
*/
|
||||||
|
private final LoadingCache<Object, Object> PRODUCER_CACHE = CacheBuilder.newBuilder()
|
||||||
|
.expireAfterAccess(Duration.ofMinutes(30))
|
||||||
|
.removalListener(notification -> {
|
||||||
|
Object producer = notification.getValue();
|
||||||
|
if (producer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
closeProducer(producer);
|
||||||
|
log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.build(new CacheLoader<Object, Object>() {
|
||||||
|
@Override
|
||||||
|
public Object load(Object config) throws Exception {
|
||||||
|
Object producer = initProducer(config);
|
||||||
|
log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config);
|
||||||
|
return producer;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取生产者
|
||||||
|
*
|
||||||
|
* @param config 配置信息
|
||||||
|
* @return 生产者对象
|
||||||
|
*/
|
||||||
|
protected Object getProducer(Object config) throws Exception {
|
||||||
|
return PRODUCER_CACHE.get(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化生产者
|
||||||
|
*
|
||||||
|
* @param config 配置信息
|
||||||
|
* @return 生产者对象
|
||||||
|
* @throws Exception 如果初始化失败
|
||||||
|
*/
|
||||||
|
protected abstract Object initProducer(Object config) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关闭生产者
|
||||||
|
*
|
||||||
|
* @param producer 生产者对象
|
||||||
|
*/
|
||||||
|
protected abstract void closeProducer(Object producer);
|
||||||
|
|
||||||
|
}
|
|
@ -3,9 +3,6 @@ package cn.iocoder.yudao.module.iot.service.rule.action.databridge;
|
||||||
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
|
import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotDataBridgeDO;
|
||||||
import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
|
import cn.iocoder.yudao.module.iot.enums.rule.IotDataBridgTypeEnum;
|
||||||
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
import cn.iocoder.yudao.module.iot.mq.message.IotDeviceMessage;
|
||||||
import com.google.common.cache.CacheBuilder;
|
|
||||||
import com.google.common.cache.CacheLoader;
|
|
||||||
import com.google.common.cache.LoadingCache;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
import org.apache.rocketmq.client.producer.DefaultMQProducer;
|
||||||
import org.apache.rocketmq.client.producer.SendResult;
|
import org.apache.rocketmq.client.producer.SendResult;
|
||||||
|
@ -14,9 +11,7 @@ import org.apache.rocketmq.common.message.Message;
|
||||||
import org.apache.rocketmq.remoting.common.RemotingHelper;
|
import org.apache.rocketmq.remoting.common.RemotingHelper;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* RocketMQ 的 {@link IotDataBridgeExecute} 实现类
|
* RocketMQ 的 {@link IotDataBridgeExecute} 实现类
|
||||||
|
@ -25,41 +20,7 @@ import java.util.concurrent.Executors;
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {
|
public class IotRocketMQDataBridgeExecute extends AbstractCacheableDataBridgeExecute {
|
||||||
|
|
||||||
/**
|
|
||||||
* 针对 {@link IotDataBridgeDO.RocketMQConfig} 的 DefaultMQProducer 缓存
|
|
||||||
*/
|
|
||||||
// TODO @puhui999:因为 kafka 之类也存在这个情况,是不是得搞个抽象类。提供一个 initProducer,和 closeProducer 方法
|
|
||||||
private final LoadingCache<IotDataBridgeDO.RocketMQConfig, DefaultMQProducer> PRODUCER_CACHE = CacheBuilder.newBuilder()
|
|
||||||
.refreshAfterWrite(Duration.ofMinutes(10)) // TODO puhui999:应该是 read 30 分钟哈
|
|
||||||
// 增加移除监听器,自动关闭 producer
|
|
||||||
.removalListener(notification -> {
|
|
||||||
DefaultMQProducer producer = (DefaultMQProducer) notification.getValue();
|
|
||||||
// TODO puhui999:if return,更简短哈
|
|
||||||
if (producer != null) {
|
|
||||||
try {
|
|
||||||
producer.shutdown();
|
|
||||||
log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已关闭]", notification.getKey());
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("[PRODUCER_CACHE][配置({}) 对应的 producer 关闭失败]", notification.getKey(), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// TODO @puhui999:就同步哈,不用异步处理。
|
|
||||||
// 通过 asyncReloading 实现全异步加载,包括 refreshAfterWrite 被阻塞的加载线程
|
|
||||||
.build(CacheLoader.asyncReloading(new CacheLoader<IotDataBridgeDO.RocketMQConfig, DefaultMQProducer>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DefaultMQProducer load(IotDataBridgeDO.RocketMQConfig config) throws Exception {
|
|
||||||
DefaultMQProducer producer = new DefaultMQProducer(config.getGroup());
|
|
||||||
producer.setNamesrvAddr(config.getNameServer());
|
|
||||||
producer.start();
|
|
||||||
log.info("[PRODUCER_CACHE][配置({}) 对应的 producer 已创建并启动]", config);
|
|
||||||
return producer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}, Executors.newCachedThreadPool()));
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) {
|
public void execute(IotDeviceMessage message, IotDataBridgeDO dataBridge) {
|
||||||
|
@ -74,7 +35,7 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {
|
||||||
private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) {
|
private void executeRocketMQ(IotDeviceMessage message, IotDataBridgeDO.RocketMQConfig config) {
|
||||||
try {
|
try {
|
||||||
// 1. 获取或创建 Producer
|
// 1. 获取或创建 Producer
|
||||||
DefaultMQProducer producer = PRODUCER_CACHE.get(config);
|
DefaultMQProducer producer = (DefaultMQProducer) getProducer(config);
|
||||||
|
|
||||||
// 2.1 创建消息对象,指定Topic、Tag和消息体
|
// 2.1 创建消息对象,指定Topic、Tag和消息体
|
||||||
Message msg = new Message(
|
Message msg = new Message(
|
||||||
|
@ -95,6 +56,22 @@ public class IotRocketMQDataBridgeExecute implements IotDataBridgeExecute {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Object initProducer(Object config) throws Exception {
|
||||||
|
IotDataBridgeDO.RocketMQConfig rocketMQConfig = (IotDataBridgeDO.RocketMQConfig) config;
|
||||||
|
DefaultMQProducer producer = new DefaultMQProducer(rocketMQConfig.getGroup());
|
||||||
|
producer.setNamesrvAddr(rocketMQConfig.getNameServer());
|
||||||
|
producer.start();
|
||||||
|
return producer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void closeProducer(Object producer) {
|
||||||
|
if (producer instanceof DefaultMQProducer) {
|
||||||
|
((DefaultMQProducer) producer).shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO @芋艿:测试代码,后续清理
|
// TODO @芋艿:测试代码,后续清理
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
// 1. 创建一个共享的实例
|
// 1. 创建一个共享的实例
|
||||||
|
|
Loading…
Reference in New Issue