package org.rocketmq.starter.core.consumer; import org.rocketmq.starter.RocketMQConsumerListener; import org.rocketmq.starter.annotation.RocketMQListener; import org.rocketmq.starter.annotation.RocketMQMessage; import org.rocketmq.starter.exception.MethodNotSupportException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.MethodIntrospector; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.util.CollectionUtils; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * @author He Jialin */ public class SimpleListenerFactory implements InitializingBean, ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(SimpleListenerFactory.class); private Map<String, RocketMQConsumerListener> allListeners; private MethodResolver resolver; private ApplicationContext context; SimpleListenerFactory() { this.resolver = new MethodResolver(); } private RocketMQConsumerListener createRocketMqConsumerListener(SubscriptionGroup subscriptionGroup) { RocketMQListenerMethodAdapter adapter = new RocketMQListenerMethodAdapter(subscriptionGroup); adapter.setInvoker(context.getBean(MethodInvoker.class)); return adapter; } public Map<String, RocketMQConsumerListener> getAllListeners() { return allListeners; } @Override public void afterPropertiesSet() { allListeners = new HashMap<>(); Map<String, SubscriptionGroup> subscriptionGroups = this.resolver.getSubscriptionGroups(); subscriptionGroups.forEach((topic, subscriptionGroup) -> allListeners.put(topic, createRocketMqConsumerListener(subscriptionGroup))); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; this.resolver.setApplicationContext(applicationContext); } private class MethodResolver implements ApplicationContextAware { private ApplicationContext context; private Map<String, SubscriptionGroup> subscriptionGroups = new HashMap<>(); private boolean initSubscription = false; Map<String, SubscriptionGroup> getSubscriptionGroups() { if (!initSubscription) { resolveListenerMethod(); } return subscriptionGroups; } void resolveListenerMethod() { context.getBeansWithAnnotation(RocketMQListener.class).forEach((beanName, obj) -> { Map<Method, RocketMQMessage> annotatedMethods = MethodIntrospector.selectMethods(obj.getClass(), (MethodIntrospector.MetadataLookup<RocketMQMessage>) method -> AnnotatedElementUtils .findMergedAnnotation(method, RocketMQMessage.class)); initSubscriptionGroup(annotatedMethods, obj); }); this.initSubscription = true; } private void initSubscriptionGroup(Map<Method, RocketMQMessage> annotatedMethod, Object target) { if (!CollectionUtils.isEmpty(annotatedMethod)) { annotatedMethod.forEach((method, listener) -> { validateMethod(method); RocketMQListener rocketMQListener = method.getDeclaringClass().getAnnotation(RocketMQListener.class); String topic = rocketMQListener.topic(); String tag = listener.tag(); if (subscriptionGroups.containsKey(topic)) { subscriptionGroups.get(topic).putTagToGroup(tag, method); } else { SubscriptionGroup subscriptionGroup = new SubscriptionGroup(topic); subscriptionGroup.putTagToGroup(tag, method); subscriptionGroup.setTarget(target); subscriptionGroups.put(topic, subscriptionGroup); } }); } } private void validateMethod(Method method) { if (method.getParameterCount() > 2) { throw new MethodNotSupportException("method: " + method + " 参数列表不被支持"); } boolean typeSupport = Arrays.stream(method.getParameterTypes()).allMatch(parmType -> parmType.equals(method .getAnnotation (RocketMQMessage.class).messageClass()) || parmType.equals(MessageContext.class)); if (!typeSupport) { throw new MethodNotSupportException("方法参数中含有不被支持的类型"); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext; } } }