mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2025-01-19 19:50:06 +08:00
完成基础的 stream 封装
This commit is contained in:
parent
9c76fd4b69
commit
d6cc9e23a3
@ -83,12 +83,15 @@ public class RedisConfig {
|
|||||||
redisTemplate.getRequiredConnectionFactory(), containerOptions);
|
redisTemplate.getRequiredConnectionFactory(), containerOptions);
|
||||||
|
|
||||||
// 第二步,注册监听器,消费对应的 Stream 主题
|
// 第二步,注册监听器,消费对应的 Stream 主题
|
||||||
String consumerName = buildConsumerName();
|
// String consumerName = buildConsumerName();
|
||||||
|
String consumerName = "110";
|
||||||
listeners.forEach(listener -> {
|
listeners.forEach(listener -> {
|
||||||
// 创建 listener 对应的消费者分组
|
// 创建 listener 对应的消费者分组
|
||||||
try {
|
try {
|
||||||
redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup());
|
redisTemplate.opsForStream().createGroup(listener.getStreamKey(), listener.getGroup());
|
||||||
} catch (Exception ignore) {}
|
} catch (Exception ignore) {}
|
||||||
|
// 设置 listener 对应的 redisTemplate
|
||||||
|
listener.setRedisTemplate(redisTemplate);
|
||||||
// 创建 Consumer 对象
|
// 创建 Consumer 对象
|
||||||
Consumer consumer = Consumer.from(listener.getGroup(), consumerName);
|
Consumer consumer = Consumer.from(listener.getGroup(), consumerName);
|
||||||
// 设置 Consumer 消费进度,以最小消费进度为准
|
// 设置 Consumer 消费进度,以最小消费进度为准
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
package cn.iocoder.dashboard.framework.redis.core.pubsub;
|
package cn.iocoder.dashboard.framework.redis.core.pubsub;
|
||||||
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.TypeUtil;
|
||||||
import cn.iocoder.dashboard.util.json.JsonUtils;
|
import cn.iocoder.dashboard.util.json.JsonUtils;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.data.redis.connection.Message;
|
import org.springframework.data.redis.connection.Message;
|
||||||
import org.springframework.data.redis.connection.MessageListener;
|
import org.springframework.data.redis.connection.MessageListener;
|
||||||
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
@ -62,21 +61,11 @@ public abstract class AbstractChannelMessageListener<T extends ChannelMessage> i
|
|||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Class<T> getMessageClass() {
|
private Class<T> getMessageClass() {
|
||||||
Class<?> targetClass = getClass();
|
Type type = TypeUtil.getTypeArgument(getClass(), 0);
|
||||||
while (targetClass.getSuperclass() != null) {
|
if (type == null) {
|
||||||
// 如果不是 AbstractMessageListener 父类,继续向上查找
|
|
||||||
if (targetClass.getSuperclass() != AbstractChannelMessageListener.class) {
|
|
||||||
targetClass = targetClass.getSuperclass();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 如果是 AbstractMessageListener 父类,则解析泛型
|
|
||||||
Type[] types = ((ParameterizedTypeImpl) targetClass.getGenericSuperclass()).getActualTypeArguments();
|
|
||||||
if (ArrayUtil.isEmpty(types)) {
|
|
||||||
throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
|
throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
|
||||||
}
|
}
|
||||||
return (Class<T>) types[0];
|
return (Class<T>) type;
|
||||||
}
|
|
||||||
throw new IllegalStateException(String.format("类型(%s) 找不到 AbstractMessageListener 父类", getClass().getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package cn.iocoder.dashboard.framework.redis.core.stream;
|
package cn.iocoder.dashboard.framework.redis.core.stream;
|
||||||
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.TypeUtil;
|
||||||
|
import cn.iocoder.dashboard.util.json.JsonUtils;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
import lombok.SneakyThrows;
|
import lombok.SneakyThrows;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.redis.connection.stream.ObjectRecord;
|
import org.springframework.data.redis.connection.stream.ObjectRecord;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.stream.StreamListener;
|
import org.springframework.data.redis.stream.StreamListener;
|
||||||
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
import java.lang.reflect.Type;
|
||||||
|
|
||||||
@ -33,9 +35,14 @@ public abstract class AbstractStreamMessageListener<T extends StreamMessage>
|
|||||||
/**
|
/**
|
||||||
* Redis 消费者分组,默认使用 spring.application.name 名字
|
* Redis 消费者分组,默认使用 spring.application.name 名字
|
||||||
*/
|
*/
|
||||||
@Value("spring.application.name")
|
@Value("${spring.application.name}")
|
||||||
@Getter
|
@Getter
|
||||||
private String group;
|
private String group;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
private RedisTemplate<String, ?> redisTemplate;
|
||||||
|
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
protected AbstractStreamMessageListener() {
|
protected AbstractStreamMessageListener() {
|
||||||
@ -45,10 +52,16 @@ public abstract class AbstractStreamMessageListener<T extends StreamMessage>
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(ObjectRecord<String, String> message) {
|
public void onMessage(ObjectRecord<String, String> message) {
|
||||||
System.out.println(message);
|
// 消费消息
|
||||||
if (true) {
|
T messageObj = JsonUtils.parseObject(message.getValue(), messageType);
|
||||||
// throw new IllegalStateException("测试下");
|
this.onMessage(messageObj);
|
||||||
}
|
// ack 消息消费完成
|
||||||
|
redisTemplate.opsForStream().acknowledge(group, message);
|
||||||
|
// TODO 芋艿:需要额外考虑以下几个点:
|
||||||
|
// 1. 处理异常的情况
|
||||||
|
// 2. 发送日志;以及事务的结合
|
||||||
|
// 3. 消费日志;以及通用的幂等性
|
||||||
|
// 4. 消费失败的重试,https://zhuanlan.zhihu.com/p/60501638
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,23 +77,12 @@ public abstract class AbstractStreamMessageListener<T extends StreamMessage>
|
|||||||
* @return 消息类型
|
* @return 消息类型
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
// TODO 芋艿:稍后重构
|
|
||||||
private Class<T> getMessageClass() {
|
private Class<T> getMessageClass() {
|
||||||
Class<?> targetClass = getClass();
|
Type type = TypeUtil.getTypeArgument(getClass(), 0);
|
||||||
while (targetClass.getSuperclass() != null) {
|
if (type == null) {
|
||||||
// 如果不是 AbstractMessageListener 父类,继续向上查找
|
|
||||||
if (targetClass.getSuperclass() != AbstractStreamMessageListener.class) {
|
|
||||||
targetClass = targetClass.getSuperclass();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// 如果是 AbstractMessageListener 父类,则解析泛型
|
|
||||||
Type[] types = ((ParameterizedTypeImpl) targetClass.getGenericSuperclass()).getActualTypeArguments();
|
|
||||||
if (ArrayUtil.isEmpty(types)) {
|
|
||||||
throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
|
throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
|
||||||
}
|
}
|
||||||
return (Class<T>) types[0];
|
return (Class<T>) type;
|
||||||
}
|
|
||||||
throw new IllegalStateException(String.format("类型(%s) 找不到 AbstractStreamMessageListener 父类", getClass().getName()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,16 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.mail;
|
|||||||
|
|
||||||
import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
|
import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
|
||||||
import cn.iocoder.dashboard.modules.system.mq.message.mail.SysMailSendMessage;
|
import cn.iocoder.dashboard.modules.system.mq.message.mail.SysMailSendMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@Slf4j
|
||||||
public class SysMailSendConsumer extends AbstractStreamMessageListener<SysMailSendMessage> {
|
public class SysMailSendConsumer extends AbstractStreamMessageListener<SysMailSendMessage> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(SysMailSendMessage message) {
|
public void onMessage(SysMailSendMessage message) {
|
||||||
|
log.info("[onMessage][消息内容({})]", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,16 @@ package cn.iocoder.dashboard.modules.system.mq.consumer.sms;
|
|||||||
|
|
||||||
import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
|
import cn.iocoder.dashboard.framework.redis.core.stream.AbstractStreamMessageListener;
|
||||||
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
|
import cn.iocoder.dashboard.modules.system.mq.message.sms.SysSmsSendMessage;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
|
@Slf4j
|
||||||
public class SysSmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> {
|
public class SysSmsSendConsumer extends AbstractStreamMessageListener<SysSmsSendMessage> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessage(SysSmsSendMessage message) {
|
public void onMessage(SysSmsSendMessage message) {
|
||||||
System.out.println(message);
|
log.info("[onMessage][消息内容({})]", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user