自定义注解,mq消费

1.解析注解方式的mq消费者

2.注解的定义

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JmqListener {

    String id() default "";

    String[] topics() default  {};
}

3.注解的使用

@Component
public class MqConsumer {

@JmqListener(id = "alarmRecordsConsumer", topics = {"${alarmRecordsConsumer.receive.alarm.topic}"})
public void onMessage(List<Message> messages)  {}
}

4.注解如何生效的

4.1 定义了一个实现了BeanPostProcessor接口的实现类JmqListenerRegister

package com.xx.jmq.client.springboot.annotation;

import com.xx.jmq.client.consumer.Consumer;
import com.xx.jmq.client.consumer.MessageListener;
import com.xx.jmq.client.springboot.configuration.JmqClient;
import com.xx.jmq.client.springboot.configuration.JmqConfigurationProperties;
import com.xx.jmq.common.message.Message;
import com.xx.jmq.client.springboot.adaptor.MessageListenerReflectAdapter;
import com.xx.jmq.client.springboot.configuration.policy.JmqConsumerPolicy;
import com.xx.jmq.client.springboot.support.ConsumerContainer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Objects;

public class JmqListenerRegister implements BeanPostProcessor, EmbeddedValueResolverAware, ApplicationContextAware {

    private static final Logger logger = LoggerFactory.getLogger(JmqListenerRegister.class);

    private final JmqConfigurationProperties jmqConfigurationProperties;

    private GenericApplicationContext applicationContext;

    private StringValueResolver stringValueResolver;

    public JmqListenerRegister(JmqConfigurationProperties jmqConfigurationProperties) {
        this.jmqConfigurationProperties = jmqConfigurationProperties;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = AopUtils.getTargetClass(bean);
        for (Method method : beanClass.getDeclaredMethods()) {
            JmqListener jmqListenerAnnotation = AnnotationUtils.findAnnotation(method, JmqListener.class);
            if (jmqListenerAnnotation == null) {
                continue;
            }
            MessageListener messageListener = getMethodMessageListener(bean, method);
            JmqClient<JmqConsumerPolicy> jmqClient = jmqConfigurationProperties.getConsumers().get(jmqListenerAnnotation.id());
            if (jmqClient == null || !jmqClient.getEnabled()) {
                continue;
            }
            if (jmqClient.getPolicy() == null) {
                if (jmqConfigurationProperties.getGlobalConsumerPolicy() != null) {
                    jmqClient.setPolicy(jmqConfigurationProperties.getGlobalConsumerPolicy());
                } else {
                    jmqClient.setPolicy(new JmqConsumerPolicy());
                }
            }
            registerListener(jmqListenerAnnotation, jmqClient, messageListener);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
        return bean;
    }

    protected MessageListener getMethodMessageListener(Object bean, Method method) {
        Class<?>[] parameterTypes = method.getParameterTypes();
        Type[] genericParameterTypes = method.getGenericParameterTypes();

        boolean isListener = (parameterTypes.length == 1 &&
                genericParameterTypes[0].getTypeName().equals(String.format("java.util.List<%s>", Message.class.getName())));

        if (!isListener) {
            throw new IllegalArgumentException("listener parameters error, need MessageListener.onMessage");
        }
        return new MessageListenerReflectAdapter(bean, method);
    }

    protected void registerListener(JmqListener jmqListener, JmqClient<JmqConsumerPolicy> jmqClient, MessageListener messageListener) {
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        if (!applicationContext.containsBean(jmqListener.id())) {
            ConsumerContainer consumerContainer = new ConsumerContainer(jmqClient);
            Object wrapperBean = beanFactory.initializeBean(consumerContainer, "consumerContainer." + jmqListener.id());
            beanFactory.registerSingleton(jmqListener.id(), Objects.requireNonNull(wrapperBean));
            logger.info("Register jmq consumer: {}", jmqClient.getId());
            Consumer consumer = consumerContainer.getObject();
            Assert.notNull(consumer, "consumer can not be null");
            for (String topic : jmqListener.topics()) {
                consumer.subscribe(stringValueResolver.resolveStringValue(topic), messageListener);
            }
        } else {
            Consumer consumer = applicationContext.getBean(jmqListener.id(), Consumer.class);
            for (String topic : jmqListener.topics()) {
                consumer.subscribe(stringValueResolver.resolveStringValue(topic), messageListener);
            }
        }
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (GenericApplicationContext) applicationContext;
    }

    @Override
    public void setEmbeddedValueResolver(@NonNull StringValueResolver stringValueResolver) {
        this.stringValueResolver = stringValueResolver;
    }
}

4.2 BeanPostProcessor接口有什么作用,为什么要定义类来实现它

BeanPostProcessor是Spring IOC容器给我们提供的一个扩展接口。,他的作用主要是如果我们需要在Spring 容器完成 Bean 的实例化、配置和其他的初始化前后添加一些自己的逻辑处理,我们就可以定义一个或者多个 BeanPostProcessor 接口的实现,然后注册到容器中。
这样MqConsumer类在被spring加载并实例化的时候,会自动执行了JmqListenerRegister中的postProcessBeforeInitialization方法

4.3 Sring加载bean的时候会自动找到实现了BeanPostProcessor接口的实现类,并执行接口里面定义的方法

@Override
   public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
   		throws BeansException {

   	Object result = existingBean;
   	for (BeanPostProcessor processor : getBeanPostProcessors()) {
   		Object current = processor.postProcessBeforeInitialization(result, beanName);
   		if (current == null) {
   			return result;
   		}
   		result = current;
   	}
   	return result;
   }

4.4 JmqListenerRegister的postProcessBeforeInitialization方法,实例初始化之前执行

@Override
   public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       Class<?> beanClass = AopUtils.getTargetClass(bean); // 获取当时实例化的bean对象的类
       for (Method method : beanClass.getDeclaredMethods()) {
   	    .// 判断当前方法是否带JmqListener的注解
           JmqListener jmqListenerAnnotation = AnnotationUtils.findAnnotation(method, JmqListener.class); 
           if (jmqListenerAnnotation == null) {
               continue;
           }
   		// 创建listener
           MessageListener messageListener = getMethodMessageListener(bean, method);
   		// 创建jmqClient
           JmqClient<JmqConsumerPolicy> jmqClient = jmqConfigurationProperties.getConsumers().get(jmqListenerAnnotation.id());
           if (jmqClient == null || !jmqClient.getEnabled()) {
               continue;
           }
           if (jmqClient.getPolicy() == null) {
               if (jmqConfigurationProperties.getGlobalConsumerPolicy() != null) {
                   jmqClient.setPolicy(jmqConfigurationProperties.getGlobalConsumerPolicy());
               } else {
                   jmqClient.setPolicy(new JmqConsumerPolicy());
               }
           }
           registerListener(jmqListenerAnnotation, jmqClient, messageListener);
       }
       return bean;
   }
   
   // 注册listener
protected void registerListener(JmqListener jmqListener, JmqClient<JmqConsumerPolicy> jmqClient, MessageListener messageListener) {
       ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
       if (!applicationContext.containsBean(jmqListener.id())) {
           ConsumerContainer consumerContainer = new ConsumerContainer(jmqClient);
           Object wrapperBean = beanFactory.initializeBean(consumerContainer, "consumerContainer." + jmqListener.id());
           beanFactory.registerSingleton(jmqListener.id(), Objects.requireNonNull(wrapperBean));
           logger.info("Register jmq consumer: {}", jmqClient.getId());
           Consumer consumer = consumerContainer.getObject();
           Assert.notNull(consumer, "consumer can not be null");
           for (String topic : jmqListener.topics()) {
               consumer.subscribe(stringValueResolver.resolveStringValue(topic), messageListener);
           }
       } else {
           Consumer consumer = applicationContext.getBean(jmqListener.id(), Consumer.class);
           for (String topic : jmqListener.topics()) {
   		   // consumer消费,绑定listener,listener里又绑定了method,method反射invoke去执行
               consumer.subscribe(stringValueResolver.resolveStringValue(topic), messageListener);
           }
       }
   }
   
protected MessageListener getMethodMessageListener(Object bean, Method method) {
       Class<?>[] parameterTypes = method.getParameterTypes();
       Type[] genericParameterTypes = method.getGenericParameterTypes();

       boolean isListener = (parameterTypes.length == 1 &&
               genericParameterTypes[0].getTypeName().equals(String.format("java.util.List<%s>", Message.class.getName())));

       if (!isListener) {
           throw new IllegalArgumentException("listener parameters error, need MessageListener.onMessage");
       }
       return new MessageListenerReflectAdapter(bean, method);
   }


MessageListenerReflectAdapter的定义,还用到了适配器模式

package com.jd.jmq.client.springboot.adaptor;

import com.jd.jmq.client.consumer.MessageListener;
import com.jd.jmq.common.message.Message;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

public class MessageListenerReflectAdapter implements MessageListener {

    private final Method method;
    private final Object instance;

    public MessageListenerReflectAdapter(Object instance, Method method) {
        this.instance = instance;
        this.method = method;
        this.method.setAccessible(true);
    }

    @Override
    public void onMessage(List<Message> messages) {
        try {
            method.invoke(instance, messages);
        } catch (InvocationTargetException e) {
            if (e.getMessage() == null) {
                throw new RuntimeException(e.getCause());
            } else {
                throw new RuntimeException(e);
            }
        } catch (Exception e) {
            throw new RuntimeException("consume error", e);
        }
    }
}

4.5 JmqListenerRegister的postProcessAfterInitialization方法,实例初始化之前执行

 @Override
   public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
       return bean;
   }
posted @ 2023-06-08 17:25  SpecialSpeculator  阅读(127)  评论(0编辑  收藏  举报