搭配SpringEvent简单实现注解式RocketMQ Consumer

66 阅读1分钟

最近在公司实习的时候看到代代码里面有这样的实现,记录一下

  1. 首先我们需要先定义一个注解用来保存 Consumer 的一些参数
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MessageQueue {
    String topic();
    String tag() default "";
    String consumeGroup() default "";
}
  1. 设置几个 Consumer Bean 并对其中的方法使用注解
@Component
public class Consumer1 {
    @MessageQueue(topic = "aa", consumeGroup = "test")
    public void test(String msg) {
        System.out.println("Consumer1 receive msg:" + msg);
    }
}

@Component
public class Consumer2 {
    @MessageQueue(topic = "aa", consumeGroup = "test2")
    public void test(String msg) {
        System.out.println("Consumer2 receive msg:" + msg);
    }
}
  1. 监听ApplicationStartedEvent遍历所有已初始化完的 Bean 并利用反射获取被注解的方法,之后使用 rocketmq-client 里的 Consumer 在回调函数里面调用这个方法
@Component
public class EventHolder {
    // rocketmq proxy
    String proxyHost = "127.0.0.1:8081";
    Set<PushConsumer> consumers = new HashSet<>();

    @EventListener
    public void onEvent(ApplicationStartedEvent event) throws ClientException {
        ConfigurableApplicationContext context = event.getApplicationContext();
        // 遍历所有的Bean
        for (String beanName : context.getBeanDefinitionNames()) {
            // 获取Bean
            Object bean = context.getBean(beanName);
            // 使用反射根据注解获取对应的方法Method
            Class<?> clazz = bean.getClass();
            for (Method method : clazz.getMethods()) {
                // 获取注解
                MessageQueue messageQueue = method.getAnnotation(MessageQueue.class);
                // 如果有注解,就调用对应的方法
                if (messageQueue != null) {
                    String topic = messageQueue.topic();
                    String tag = messageQueue.tag();
                    String consumeGroup = messageQueue.consumeGroup();

                    // 构造一个Consumer
                    ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder().setEndpoints(proxyHost).build();
                    ClientServiceProvider clientServiceProvider = ClientServiceProvider.loadService();
                    PushConsumer pushConsumer = clientServiceProvider.newPushConsumerBuilder()
                            .setClientConfiguration(clientConfiguration)
                            .setConsumerGroup(consumeGroup)
                            .setSubscriptionExpressions(Collections.singletonMap(topic, new FilterExpression(tag.isEmpty() ? "*" : tag, FilterExpressionType.TAG)))
                            .setMessageListener((messageView) -> {
                                String message = convertByteBufferToString(messageView.getBody());
                                try {
                                    // 调用方法
                                    method.invoke(bean, message);
                                } catch (IllegalAccessException e) {
                                    throw new RuntimeException(e);
                                } catch (InvocationTargetException e) {
                                    throw new RuntimeException(e);
                                }
                                return ConsumeResult.SUCCESS;
                            })
                            .build();
                    consumers.add(pushConsumer);
                }
            }
        }
    }

    /**
     * 将 ByteBuffer 转换为字符串
     *
     * @param byteBuffer ByteBuffer 对象
     * @return 转换后的字符串
     */
    public static String convertByteBufferToString(ByteBuffer byteBuffer) {
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes); // 从 ByteBuffer 中读取字节
        return new String(bytes, StandardCharsets.UTF_8); // 使用 UTF-8 字符集转换为字符串
    }
}