Browse Source

feat: 数据消费改用注解方式

master
xsx 2 years ago
parent
commit
126cf03121
  1. 34
      im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java
  2. 43
      im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java
  3. 47
      im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java
  4. 22
      im-client/src/main/java/com/bx/imclient/task/SystemMessageResultResultTask.java
  5. 16
      im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConsumer.java
  6. 24
      im-commom/src/main/java/com/bx/imcommon/mq/RedisMQPullTask.java
  7. 38
      im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java
  8. 25
      im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java
  9. 26
      im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java
  10. 8
      im-server/src/main/java/com/bx/imserver/task/PullSystemMessageTask.java

34
im-client/src/main/java/com/bx/imclient/task/AbstractMessageResultTask.java

@ -1,37 +1,21 @@
package com.bx.imclient.task;
import com.bx.imcommon.util.ThreadPoolExecutorFactory;
import lombok.SneakyThrows;
import cn.hutool.core.util.StrUtil;
import com.bx.imcommon.mq.RedisMQConsumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Value;
@Slf4j
public abstract class AbstractMessageResultTask implements CommandLineRunner {
public abstract class AbstractMessageResultTask<T> extends RedisMQConsumer<T> {
private static final ScheduledThreadPoolExecutor EXECUTOR_SERVICE = ThreadPoolExecutorFactory.getThreadPoolExecutor();
@Value("${spring.application.name}")
private String appName;
@Override
public void run(String... args) {
// 初始化定时器
EXECUTOR_SERVICE.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
try {
pullMessage();
} catch (Exception e) {
log.error("任务调度异常", e);
}
if (!EXECUTOR_SERVICE.isShutdown()) {
EXECUTOR_SERVICE.schedule(this,100, TimeUnit.MICROSECONDS);
}
}
});
public String generateKey() {
return StrUtil.join(":", super.generateKey(), appName);
}
public abstract void pullMessage() throws InterruptedException;
}

43
im-client/src/main/java/com/bx/imclient/task/GroupMessageResultResultTask.java

@ -1,58 +1,27 @@
package com.bx.imclient.task;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bx.imclient.listener.MessageListenerMulticaster;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMListenerType;
import com.bx.imcommon.model.IMSendResult;
import com.bx.imcommon.mq.RedisMQTemplate;
import com.bx.imcommon.mq.RedisMQListener;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@Component
@RequiredArgsConstructor
public class GroupMessageResultResultTask extends AbstractMessageResultTask {
@Autowired
private RedisMQTemplate redisMQTemplate;
@Value("${spring.application.name}")
private String appName;
@Value("${im.result.batch:100}")
private int batchSize;
@RedisMQListener(queue = IMRedisKey.IM_RESULT_GROUP_QUEUE, batchSize = 100)
public class GroupMessageResultResultTask extends AbstractMessageResultTask<IMSendResult> {
private final MessageListenerMulticaster listenerMulticaster;
@Override
public void pullMessage() {
List<IMSendResult> results;
do {
results = loadBatch();
if(!results.isEmpty()){
listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE, results);
}
} while (results.size() >= batchSize);
public void onMessage(List<IMSendResult> results) {
listenerMulticaster.multicast(IMListenerType.GROUP_MESSAGE, results);
}
List<IMSendResult> loadBatch() {
String key = StrUtil.join(":", IMRedisKey.IM_RESULT_GROUP_QUEUE, appName);
//这个接口redis6.2以上才支持
//List<Object> list = redisMQTemplate.opsForList().leftPop(key, batchSize);
List<IMSendResult> results = new LinkedList<>();
JSONObject jsonObject = (JSONObject) redisMQTemplate.opsForList().leftPop(key);
while (!Objects.isNull(jsonObject) && results.size() < batchSize) {
results.add(jsonObject.toJavaObject(IMSendResult.class));
jsonObject = (JSONObject) redisMQTemplate.opsForList().leftPop(key);
}
return results;
}
}

47
im-client/src/main/java/com/bx/imclient/task/PrivateMessageResultResultTask.java

@ -1,59 +1,26 @@
package com.bx.imclient.task;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bx.imclient.listener.MessageListenerMulticaster;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMListenerType;
import com.bx.imcommon.model.IMSendResult;
import com.bx.imcommon.mq.RedisMQTemplate;
import com.bx.imcommon.mq.RedisMQListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
@RequiredArgsConstructor
public class PrivateMessageResultResultTask extends AbstractMessageResultTask {
@Autowired
private RedisMQTemplate redisMQTemplate;
@Value("${spring.application.name}")
private String appName;
@Value("${im.result.batch:100}")
private int batchSize;
@RedisMQListener(queue = IMRedisKey.IM_RESULT_PRIVATE_QUEUE, batchSize = 100)
public class PrivateMessageResultResultTask extends AbstractMessageResultTask<IMSendResult> {
private final MessageListenerMulticaster listenerMulticaster;
@Override
public void pullMessage() {
List<IMSendResult> results;
do {
results = loadBatch();
if(!results.isEmpty()){
listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, results);
}
} while (results.size() >= batchSize);
}
List<IMSendResult> loadBatch() {
String key = StrUtil.join(":", IMRedisKey.IM_RESULT_PRIVATE_QUEUE, appName);
//这个接口redis6.2以上才支持
//List<Object> list = redisMQTemplate.opsForList().leftPop(key, batchSize);
List<IMSendResult> results = new LinkedList<>();
JSONObject jsonObject = (JSONObject) redisMQTemplate.opsForList().leftPop(key);
while (!Objects.isNull(jsonObject) && results.size() < batchSize) {
results.add(jsonObject.toJavaObject(IMSendResult.class));
jsonObject = (JSONObject) redisMQTemplate.opsForList().leftPop(key);
}
return results;
public void onMessage(List<IMSendResult> results) {
listenerMulticaster.multicast(IMListenerType.PRIVATE_MESSAGE, results);
}
}

22
im-client/src/main/java/com/bx/imclient/task/SystemMessageResultResultTask.java

@ -1,32 +1,19 @@
package com.bx.imclient.task;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.bx.imclient.listener.MessageListenerMulticaster;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMListenerType;
import com.bx.imcommon.model.IMSendResult;
import com.bx.imcommon.mq.RedisMQConsumer;
import com.bx.imcommon.mq.RedisMQListener;
import com.bx.imcommon.mq.RedisMQTemplate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
@Slf4j
@Component
@RequiredArgsConstructor
@RedisMQListener(queue = IMRedisKey.IM_RESULT_SYSTEM_QUEUE, batchSize = 100, period = 100)
public class SystemMessageResultResultTask extends RedisMQConsumer<IMSendResult> {
@Value("${spring.application.name}")
private String appName;
@RedisMQListener(queue = IMRedisKey.IM_RESULT_SYSTEM_QUEUE, batchSize = 100)
public class SystemMessageResultResultTask extends AbstractMessageResultTask<IMSendResult> {
private final MessageListenerMulticaster listenerMulticaster;
@ -35,9 +22,4 @@ public class SystemMessageResultResultTask extends RedisMQConsumer<IMSendResult>
listenerMulticaster.multicast(IMListenerType.SYSTEM_MESSAGE, results);
}
@Override
public String generateKey() {
return StrUtil.join(":", IMRedisKey.IM_RESULT_SYSTEM_QUEUE, appName);
}
}

16
im-commom/src/main/java/com/bx/imcommon/mq/RedisMQConsumer.java

@ -7,13 +7,29 @@ import java.util.List;
*/
public abstract class RedisMQConsumer<T> {
/**
* 消费消息回调(单条)
*/
public void onMessage(T data){}
/**
* 消费消息回调(批量)
*/
public void onMessage(List<T> datas){}
/**
* 生成redis队列完整key
*/
public String generateKey(){
// 默认队列名就是redis的key
RedisMQListener annotation = this.getClass().getAnnotation(RedisMQListener.class);
return annotation.queue();
}
/**
* 队列是否就绪返回true才会开始消费
*/
public Boolean isReady(){
return true;
}
}

24
im-commom/src/main/java/com/bx/imcommon/mq/RedisMQPullTask.java

@ -49,18 +49,20 @@ public class RedisMQPullTask implements CommandLineRunner {
public void run() {
List<Object> datas = new LinkedList<>();
try {
// 拉取一个批次的数据
List<Object> objects = pullBatch(key, batchSize);
for (Object obj : objects) {
if (obj instanceof JSONObject) {
JSONObject jsonObject = (JSONObject)obj;
Object data = jsonObject.toJavaObject(type);
consumer.onMessage(data);
datas.add(data);
if(consumer.isReady()){
// 拉取一个批次的数据
List<Object> objects = pullBatch(key, batchSize);
for (Object obj : objects) {
if (obj instanceof JSONObject) {
JSONObject jsonObject = (JSONObject)obj;
Object data = jsonObject.toJavaObject(type);
consumer.onMessage(data);
datas.add(data);
}
}
if(!datas.isEmpty()){
consumer.onMessage(datas);
}
}
if(!datas.isEmpty()){
consumer.onMessage(datas);
}
} catch (Exception e) {
log.error("数据消费异常,队列:{}", key, e);

38
im-server/src/main/java/com/bx/imserver/task/AbstractPullMessageTask.java

@ -1,45 +1,23 @@
package com.bx.imserver.task;
import com.bx.imcommon.util.ThreadPoolExecutorFactory;
import com.bx.imcommon.mq.RedisMQConsumer;
import com.bx.imserver.netty.IMServerGroup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import javax.annotation.PreDestroy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
public abstract class AbstractPullMessageTask implements CommandLineRunner {
private static final ScheduledThreadPoolExecutor EXECUTOR_SERVICE = ThreadPoolExecutorFactory.getThreadPoolExecutor();
public abstract class AbstractPullMessageTask<T> extends RedisMQConsumer<T> {
@Autowired
private IMServerGroup serverGroup;
@Override
public void run(String... args) {
EXECUTOR_SERVICE.execute(new Runnable() {
@SneakyThrows
@Override
public void run() {
try {
if (serverGroup.isReady()) {
pullMessage();
}
} catch (Exception e) {
log.error("任务调度异常", e);
}
if (!EXECUTOR_SERVICE.isShutdown()) {
EXECUTOR_SERVICE.schedule(this,100, TimeUnit.MICROSECONDS);
}
}
});
public String generateKey() {
return String.join(":", super.generateKey(), IMServerGroup.serverId + "");
}
public abstract void pullMessage() throws InterruptedException;
@Override
public Boolean isReady() {
return serverGroup.isReady();
}
}

25
im-server/src/main/java/com/bx/imserver/task/PullGroupMessageTask.java

@ -1,38 +1,25 @@
package com.bx.imserver.task;
import com.alibaba.fastjson.JSONObject;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMCmdType;
import com.bx.imcommon.model.IMRecvInfo;
import com.bx.imserver.netty.IMServerGroup;
import com.bx.imcommon.mq.RedisMQListener;
import com.bx.imserver.netty.processor.AbstractMessageProcessor;
import com.bx.imserver.netty.processor.ProcessorFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Slf4j
@Component
@RequiredArgsConstructor
public class PullGroupMessageTask extends AbstractPullMessageTask {
private final RedisTemplate<String, Object> redisTemplate;
@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_GROUP_QUEUE, batchSize = 10)
public class PullGroupMessageTask extends AbstractPullMessageTask<IMRecvInfo> {
@Override
public void pullMessage() {
// 从redis拉取消息
String key = String.join(":", IMRedisKey.IM_MESSAGE_GROUP_QUEUE, IMServerGroup.serverId + "");
JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key);
while (!Objects.isNull(jsonObject)) {
IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class);
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE);
processor.process(recvInfo);
// 下一条消息
jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key);
}
public void onMessage(IMRecvInfo recvInfo) {
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.GROUP_MESSAGE);
processor.process(recvInfo);
}
}

26
im-server/src/main/java/com/bx/imserver/task/PullPrivateMessageTask.java

@ -1,37 +1,25 @@
package com.bx.imserver.task;
import com.alibaba.fastjson.JSONObject;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMCmdType;
import com.bx.imcommon.model.IMRecvInfo;
import com.bx.imserver.netty.IMServerGroup;
import com.bx.imcommon.mq.RedisMQListener;
import com.bx.imserver.netty.processor.AbstractMessageProcessor;
import com.bx.imserver.netty.processor.ProcessorFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import java.util.Objects;
@Slf4j
@Component
@RequiredArgsConstructor
public class PullPrivateMessageTask extends AbstractPullMessageTask {
private final RedisTemplate<String, Object> redisTemplate;
@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, batchSize = 10)
public class PullPrivateMessageTask extends AbstractPullMessageTask<IMRecvInfo> {
@Override
public void pullMessage() {
// 从redis拉取消息
String key = String.join(":", IMRedisKey.IM_MESSAGE_PRIVATE_QUEUE, IMServerGroup.serverId + "");
JSONObject jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key);
while (!Objects.isNull(jsonObject)) {
IMRecvInfo recvInfo = jsonObject.toJavaObject(IMRecvInfo.class);
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE);
processor.process(recvInfo);
// 下一条消息
jsonObject = (JSONObject) redisTemplate.opsForList().leftPop(key);
}
public void onMessage(IMRecvInfo recvInfo) {
AbstractMessageProcessor processor = ProcessorFactory.createProcessor(IMCmdType.PRIVATE_MESSAGE);
processor.process(recvInfo);
}
}

8
im-server/src/main/java/com/bx/imserver/task/PullSystemMessageTask.java

@ -3,9 +3,7 @@ package com.bx.imserver.task;
import com.bx.imcommon.contant.IMRedisKey;
import com.bx.imcommon.enums.IMCmdType;
import com.bx.imcommon.model.IMRecvInfo;
import com.bx.imcommon.mq.RedisMQConsumer;
import com.bx.imcommon.mq.RedisMQListener;
import com.bx.imserver.netty.IMServerGroup;
import com.bx.imserver.netty.processor.AbstractMessageProcessor;
import com.bx.imserver.netty.processor.ProcessorFactory;
import lombok.extern.slf4j.Slf4j;
@ -19,7 +17,7 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
@RedisMQListener(queue = IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE,batchSize = 10)
public class PullSystemMessageTask extends RedisMQConsumer<IMRecvInfo> {
public class PullSystemMessageTask extends AbstractPullMessageTask<IMRecvInfo> {
@Override
public void onMessage(IMRecvInfo recvInfo) {
@ -27,8 +25,4 @@ public class PullSystemMessageTask extends RedisMQConsumer<IMRecvInfo> {
processor.process(recvInfo);
}
public String generateKey(){
// 队列名:im:message:system:{服务id}
return String.join(":", IMRedisKey.IM_MESSAGE_SYSTEM_QUEUE, IMServerGroup.serverId + "");
}
}

Loading…
Cancel
Save