|
@@ -1,127 +0,0 @@
|
|
-package com.chelvc.framework.rocketmq.fallback;
|
|
|
|
-
|
|
|
|
-import java.lang.reflect.Method;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.Objects;
|
|
|
|
-import java.util.stream.Stream;
|
|
|
|
-
|
|
|
|
-import com.beust.jcommander.internal.Maps;
|
|
|
|
-import com.chelvc.framework.base.context.ApplicationContextHolder;
|
|
|
|
-import com.chelvc.framework.common.util.ObjectUtils;
|
|
|
|
-import com.chelvc.framework.common.util.StringUtils;
|
|
|
|
-import com.chelvc.framework.rocketmq.annotation.RocketMQConsumer;
|
|
|
|
-import com.chelvc.framework.rocketmq.consumer.RocketMQListener;
|
|
|
|
-import lombok.NonNull;
|
|
|
|
-import lombok.extern.slf4j.Slf4j;
|
|
|
|
-import org.springframework.aop.framework.AopProxyUtils;
|
|
|
|
-import org.springframework.boot.context.event.ApplicationStartedEvent;
|
|
|
|
-import org.springframework.context.ApplicationContext;
|
|
|
|
-import org.springframework.context.ApplicationListener;
|
|
|
|
-import org.springframework.core.env.Environment;
|
|
|
|
-import org.springframework.kafka.annotation.KafkaListener;
|
|
|
|
-import org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor;
|
|
|
|
-import org.springframework.kafka.annotation.TopicPartition;
|
|
|
|
-import sun.reflect.annotation.AnnotationParser;
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * RocketMQ降级Kafka消息监听器处理器
|
|
|
|
- *
|
|
|
|
- * @author Woody
|
|
|
|
- * @date 2024/7/13
|
|
|
|
- */
|
|
|
|
-@Slf4j
|
|
|
|
-public class RocketMQListenerKafkaProcessor extends KafkaListenerAnnotationBeanPostProcessor<Object, Object>
|
|
|
|
- implements ApplicationListener<ApplicationStartedEvent> {
|
|
|
|
- /**
|
|
|
|
- * 创建Kafka消息监听器注解实例
|
|
|
|
- *
|
|
|
|
- * @param topic 消息主题
|
|
|
|
- * @param consumer RocketMQ消息监听器注解实例
|
|
|
|
- * @return Kafka消息监听器注解实例
|
|
|
|
- */
|
|
|
|
- protected KafkaListener createKafkaListener(@NonNull String topic, @NonNull RocketMQConsumer consumer) {
|
|
|
|
- Map<String, Object> properties = Maps.newHashMap();
|
|
|
|
- properties.put("id", StringUtils.EMPTY);
|
|
|
|
- properties.put("containerFactory", consumer.batch() > 1 ? "batchListenerContainerFactory" : StringUtils.EMPTY);
|
|
|
|
- properties.put("topics", new String[]{topic});
|
|
|
|
- properties.put("topicPattern", StringUtils.EMPTY);
|
|
|
|
- properties.put("topicPartitions", new TopicPartition[0]);
|
|
|
|
- properties.put("containerGroup", StringUtils.EMPTY);
|
|
|
|
- properties.put("errorHandler", StringUtils.EMPTY);
|
|
|
|
- properties.put("groupId", consumer.group());
|
|
|
|
- properties.put("idIsGroup", true);
|
|
|
|
- properties.put("clientIdPrefix", StringUtils.EMPTY);
|
|
|
|
- properties.put("beanRef", "__listener");
|
|
|
|
- properties.put("concurrency", StringUtils.EMPTY);
|
|
|
|
- properties.put("autoStartup", StringUtils.EMPTY);
|
|
|
|
- properties.put("properties", StringUtils.EMPTY_ARRAY);
|
|
|
|
- properties.put("splitIterables", true);
|
|
|
|
- properties.put("contentTypeConverter", StringUtils.EMPTY);
|
|
|
|
- properties.put("batch", String.valueOf(consumer.batch()));
|
|
|
|
- return (KafkaListener) AnnotationParser.annotationForMap(KafkaListener.class, properties);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * 注册消息监听器容器
|
|
|
|
- *
|
|
|
|
- * @param applicationContext 应用上下文
|
|
|
|
- * @param name 消息监听器名称
|
|
|
|
- * @param listener 消息监听器实例
|
|
|
|
- * @param <T> 消息对象类型
|
|
|
|
- */
|
|
|
|
- protected <T> void registerListenerContainer(@NonNull ApplicationContext applicationContext, @NonNull String name,
|
|
|
|
- @NonNull RocketMQListener<T> listener) {
|
|
|
|
- // 获取RocketMQ消息监听器注解实例
|
|
|
|
- Class<?> clazz = AopProxyUtils.ultimateTargetClass(listener);
|
|
|
|
- RocketMQConsumer consumer = clazz.getAnnotation(RocketMQConsumer.class);
|
|
|
|
- if (consumer == null) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 判断类对象是否存在相同topic @KafkaListener注解,如果存在则忽略
|
|
|
|
- Environment environment = applicationContext.getEnvironment();
|
|
|
|
- String topic = ObjectUtils.ifNull(consumer.topic(), environment::resolvePlaceholders);
|
|
|
|
- String tag = ObjectUtils.ifNull(consumer.tag(), environment::resolvePlaceholders);
|
|
|
|
- if (StringUtils.notEmpty(tag) && !Objects.equals(tag, "*")) {
|
|
|
|
- topic = topic + "-" + tag;
|
|
|
|
- }
|
|
|
|
- KafkaListener annotation = clazz.getAnnotation(KafkaListener.class);
|
|
|
|
- if (annotation != null && Stream.concat(Stream.of(annotation.topics()), Stream.of(annotation.topicPattern()))
|
|
|
|
- .filter(StringUtils::notEmpty).map(environment::resolvePlaceholders).anyMatch(topic::equals)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 判断消息消费方法是否存在相同topic @KafkaListener注解,如果存在则忽略
|
|
|
|
- Method method;
|
|
|
|
- Class<?> type = ObjectUtils.type2class(ObjectUtils.lookupSuperclassParameterized(
|
|
|
|
- clazz, RocketMQListener.class, Object.class
|
|
|
|
- ));
|
|
|
|
- try {
|
|
|
|
- method = clazz.getMethod("consume", type);
|
|
|
|
- } catch (NoSuchMethodException e) {
|
|
|
|
- log.warn("Kafka fallback method is missing: {}.({})", clazz.getName(), type.getName());
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- annotation = method.getAnnotation(KafkaListener.class);
|
|
|
|
- if (annotation != null && Stream.concat(Stream.of(annotation.topics()), Stream.of(annotation.topicPattern()))
|
|
|
|
- .filter(StringUtils::notEmpty).map(environment::resolvePlaceholders).anyMatch(topic::equals)) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // 注册Kafka消息监听器
|
|
|
|
- try {
|
|
|
|
- annotation = this.createKafkaListener(topic, consumer);
|
|
|
|
- this.processKafkaListener(annotation, method, listener, name);
|
|
|
|
- } catch (Exception e) {
|
|
|
|
- log.error("Kafka listener process failed", e);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Override
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- public void onApplicationEvent(ApplicationStartedEvent event) {
|
|
|
|
- ApplicationContext applicationContext = event.getApplicationContext();
|
|
|
|
- ApplicationContextHolder.getBeans(RocketMQListener.class)
|
|
|
|
- .forEach((name, listener) -> this.registerListenerContainer(applicationContext, name, listener));
|
|
|
|
- }
|
|
|
|
-}
|
|
|