feat(mq-starter-core): @MqListener 扫描 → MqListenerEndpoint

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-26 04:53:01 +08:00
parent 871aef64f8
commit 744115ca97
3 changed files with 78 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
package com.njcn.mq.container;
import com.njcn.mq.annotation.MqListener;
import com.njcn.mq.core.MqContext;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotatedElementUtils;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class MqListenerAnnotationBeanPostProcessor implements BeanPostProcessor {
private final List<MqListenerEndpoint> endpoints = new ArrayList<>();
public List<MqListenerEndpoint> getEndpoints() { return endpoints; }
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
for (Method m : bean.getClass().getDeclaredMethods()) {
MqListener meta = AnnotatedElementUtils.findMergedAnnotation(m, MqListener.class);
if (meta == null) continue;
Class<?>[] params = m.getParameterTypes();
if (params.length < 1 || params.length > 2) {
throw new IllegalStateException("@MqListener 方法签名须为 (payload) 或 (payload, MqContext): " + m);
}
boolean wantsContext = params.length == 2;
if (wantsContext && params[1] != MqContext.class) {
throw new IllegalStateException("@MqListener 第二参须为 MqContext: " + m);
}
Class<?> payloadType = params[0];
m.setAccessible(true);
endpoints.add(new MqListenerEndpoint(bean, m, meta, payloadType, wantsContext));
}
return bean;
}
}

View File

@@ -0,0 +1,15 @@
package com.njcn.mq.container;
import com.njcn.mq.annotation.MqListener;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.lang.reflect.Method;
@Data
@AllArgsConstructor
public class MqListenerEndpoint {
private Object bean;
private Method method;
private MqListener meta;
private Class<?> payloadType;
private boolean wantsContext;
}

View File

@@ -0,0 +1,28 @@
package com.njcn.mq.container;
import com.njcn.mq.annotation.MqListener;
import com.njcn.mq.core.MqContext;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
class MqListenerScanTest {
static class Biz {
@MqListener(topic = "LN_Topic", group = "ln_consumer")
public void onData(String msg) { }
@MqListener(topic = "T2", group = "g2")
public void onWithCtx(String msg, MqContext ctx) { }
}
@Test
void scan_findsEndpoints_withPayloadTypeAndContextFlag() {
MqListenerAnnotationBeanPostProcessor bpp = new MqListenerAnnotationBeanPostProcessor();
bpp.postProcessAfterInitialization(new Biz(), "biz");
List<MqListenerEndpoint> eps = bpp.getEndpoints();
assertEquals(2, eps.size());
MqListenerEndpoint e1 = eps.stream().filter(e -> e.getMeta().topic().equals("LN_Topic")).findFirst().orElseThrow(AssertionError::new);
assertEquals(String.class, e1.getPayloadType());
assertFalse(e1.isWantsContext());
MqListenerEndpoint e2 = eps.stream().filter(e -> e.getMeta().topic().equals("T2")).findFirst().orElseThrow(AssertionError::new);
assertTrue(e2.isWantsContext());
}
}