使用stream统一所有消息发送机制(结合rocketmq)

本文介绍了如何在SpringCloudStream框架下,使用ApacheKafka、RabbitMQ或RocketMQ等消息代理构建消息驱动的微服务应用。文章详细阐述了如何引入依赖、定义消息模块接口、抽象类和默认实体,以及如何通过@EnableBinding注解集成RocketMQ实现消息传递机制。
摘要由CSDN通过智能技术生成

项目实战

定义基础模块

首先引入依赖spring-cloud-stream

  • Spring Cloud Stream 是一个用于构建基于消息驱动微服务的框架。它是 Spring Cloud 生态系统中的一部分,提供了一种简单且强大的方式来开发基于消息的微服务应用程序。
  • Spring Cloud Stream 提供了一种声明性的方式来定义消息通道(channels)、消息处理器(processors)和绑定器(binders)。通过这种方式,开发者可以专注于业务逻辑而不必关心底层消息传递机制。它支持多种消息代理,包括 Apache Kafka、RabbitMQ、Kinesis 等。
  • 利用这个依赖当底层可以基于这个来实现不同的消息中间件
    <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

接着在核心模块里面定义消息模块顶级接口

  • boolean sendMessage(String channelName, Object payload)

    这是一个用于发送消息的方法。它接受两个参数:

    • channelName:消息通道的名称,指定消息发送到哪个通道。
    • payload:消息的载荷,即要发送的实际数据。
  • boolean sendMessage(String channelName, Object payload, Map<String,Object> headers)

    这也是一个用于发送消息的方法,与上一个方法相比,它多了一个参数 headers,用于指定消息的头部信息。

    • headers:消息的头部信息,是一个键值对形式的 Map<String, Object>,可以包含各种元数据信息。
package com.yubin.pan.stream.core;

import java.util.Map;

/**
 * 消息发送者顶级接口
 * @author yubin
 * @create 2024-04-18-9:59
 */
public interface IStreamProducer {


    /**
     * 发送消息
     * @param channelName
     * @param deploy
     * @return
     */
    boolean sendMessage(String channelName,Object deploy);



    /**
     * 发送消息
     * @param channelName
     * @param deploy
     * @return
     */
    boolean sendMessage(String channelName, Object deploy, Map<String,Object> headers);






}

接着定义消息发送顶级抽象类

  • 方法 sendMessage(String channelName, Object deploy, Map<String, Object> headers)

    • 这是 IStreamProducer 接口中的方法的实现。它负责发送消息到指定的消息通道,并执行一系列的操作:
      • 首先,对参数进行校验,确保 channelNamedeploy 不为空。
      • 然后,检查 channelMap 是否为空,如果为空则抛出异常。
      • 接着,根据 channelNamechannelMap 中获取对应的 MessageChannel
      • 创建消息对象 message,并使用 MessageBuilder 构建消息,并传入消息载荷 deploy 和消息头部 headers
      • 调用 proSend 方法,执行发送消息前的钩子函数。
      • 调用消息通道的 send 方法发送消息,并将结果存储到 result 变量中。
      • 调用 afterSend 方法,执行发送消息后的钩子函数,并将消息对象和发送结果传入。
package com.yubin.pan.stream.core;

import com.google.common.collect.Maps;
import com.imooc.pan.core.exception.RPanFrameworkException;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;

import java.util.Map;
import java.util.Objects;

/**
 * 消息发送者顶级抽象父类
 * @author yubin
 * @create 2024-04-18-10:01
 */
public abstract class AbstractStreamProducer implements IStreamProducer{


    @Autowired
    private Map<String, MessageChannel> channelMap;

    /**
     * 发送消息
     * @param channelName
     * @param deploy
     * @return
     */

    @Override
    public boolean sendMessage(String channelName, Object deploy) {
        return sendMessage(channelName,deploy, Maps.newHashMap());
    }

    /**
     * 发送消息
     *
     * 1.参数校验
     * 2.执行发送前钩子函数
     * 3.执行发送的动作
     * 发的后置钩子函数
     * 返回结果
     *
     * @param channelName
     * @param deploy
     * @param headers
     * @return
     */
    @Override
    public boolean sendMessage(String channelName, Object deploy, Map<String, Object> headers) {

        if(StringUtils.isBlank(channelName) || Objects.isNull(deploy)){
            throw  new RPanFrameworkException("the channelName or deploy can not be empty!");
        }

        if(MapUtils.isEmpty(channelMap)){
            throw new RPanFrameworkException("the channelMap can not be empty");
        }

        MessageChannel channel = channelMap.get(channelName);


        if(Objects.isNull(channel)){
            throw new RPanFrameworkException("the channel named" + channelName + "  can not be found");

        }

        Message message = MessageBuilder.createMessage(deploy, new MessageHeaders(headers));

        proSend(message);

        boolean result = channel.send(message);

        afterSend(message,result);

        return result;


    }


    /**
     * 发送消息的前置钩子函数
     * @param message
     */
    protected abstract void proSend(Message message);


    /**
     * 发送消息的后置钩子函数
     * @param message
     * @param result
     */
    protected abstract void afterSend(Message message, boolean result);

}

定义默认消息发送实体

/**
 * 默认消息发送实体
 * @author yubin
 * @create 2024-04-18-10:19
 */

@Component(value = "defaultStreamProducer")
public class DefaultStreamProducer extends AbstractStreamProducer{
    @Override
    protected void proSend(Message message) {

    }

    @Override
    protected void afterSend(Message message, boolean result) {

    }
}

有点抽象的发送者,需要把公共的消息消费者抽离出来

  • 方法 printLog(Message message)

    • 这是一个公共方法,用于打印消费者处理消息的日志。
    • 它接受一个 Message 对象作为参数,然后通过日志记录器 log 打印日志信息。
    • 日志信息包括消费者类的简单类名以及消息内容。
  • 方法 ifEmptyMessage(Message message)

    • 这是一个公共方法,用于判断消息是否为空。
    • 它接受一个 Message 对象作为参数,首先判断消息对象是否为空,如果为空则返回 true
    • 否则,从消息对象中获取消息的载荷(payload),再次判断载荷是否为空,如果为空则返回 true
    • 如果消息对象和消息载荷都不为空,则返回 false
package com.yubin.pan.stream.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.Message;

import java.util.Objects;

/**
 * 消费者的公共父类
 * 主要做公用逻辑的抽离
 * @author yubin
 * @create 2024-04-18-10:21
 */
@Slf4j
public abstract class AbstractConsumer {


    /**
     * 公用的消息打印日志
     * @param message
     */
    protected void printLog(Message message){

         log.info("{} start consume the message.the message is{}" , this.getClass().getSimpleName(),message);


    }


    /**
     * 公用的消息校验
     * @param message
     * @return
     */
    protected boolean ifEmptyMessage(Message message){
        if(Objects.isNull(message)){
            return true;
        }

        Object payload = message.getPayload();

        if(Objects.isNull(payload)){
            return true;
        }

        return false;

    }

}

集成rocketmq来实现消息传递机制

直接定义依赖就行

    <dependencies>
        <dependency>
            <groupId>com.imooc.pan</groupId>
            <artifactId>stream-core</artifactId>
            <version>1.0</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
        </dependency>

    </dependencies>

接着在业务类中创建对应东西并测试

通过使用这些通道,可以实现消息的接收和发送。这种定义方式符合 Spring Cloud Stream 的规范

  1. 常量 TEST_INPUTTEST_OUTPUT

    • 这两个常量分别定义了输入通道和输出通道的名称。
  2. 方法 testInput()

    • 这是一个用于获取测试输入通道的方法。
    • 使用 @Input(TEST_INPUT) 注解来标注这个方法,表示这是一个输入通道,名称为 TEST_INPUT
    • 返回类型为 SubscribableChannel,表示这是一个可订阅的消息通道。
  3. 方法 testOutput()

    • 这是一个用于获取测试输出通道的方法。
    • 使用 @Output(TEST_OUTPUT) 注解来标注这个方法,表示这是一个输出通道,名称为 TEST_OUTPUT
    • 返回类型为 MessageChannel,表示这是一个消息通道,用于发送消息。
/**
 * 事件通道定义类
 * @author yubin
 * @create 2024-04-18-16:20
 */
public interface PanChannels {

    String TEST_INPUT = "testInput";

    String TEST_OUTPUT = "testOutput";


    /**
     * 测试输入通道
     */
    @Input(TEST_INPUT)
    SubscribableChannel testInput();


    /**
     * 测试输出通道
     * @return
     */
    @Output(TEST_OUTPUT)
    MessageChannel testOutput();

}

启动类定义注解

@EnableBinding(PanChannels.class)

作用:

@EnableBinding(PanChannels.class) 是 Spring Cloud Stream 提供的一个注解,用于启用消息通道绑定。在 Spring Cloud Stream 中,通过 @EnableBinding 注解可以将定义的消息通道与 Spring 应用程序中的实际消息队列(如 Kafka、RabbitMQ 等)进行绑定,从而实现消息的发送和接收。

具体来说,@EnableBinding 注解接受一个或多个接口作为参数,这些接口通常被称为 "Binder interfaces",它们定义了应用程序与消息中间件之间的通信通道。在这里,PanChannels.class 是一个定义了消息通道的接口,通过 @EnableBinding(PanChannels.class) 注解,Spring Cloud Stream 将会根据 PanChannels 接口的定义,自动创建相应的消息通道并与之绑定。

这样一来,当应用程序需要发送或接收消息时,就可以直接使用 PanChannels 接口中定义的消息通道,而无需关心底层消息中间件的具体实现细节。@EnableBinding 注解会在应用程序启动时自动配置相关的消息通道,使得应用程序能够与消息中间件进行无缝集成。

  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 Spring Cloud Stream 集成 RocketMQ 可以实现消息驱动的微服务架构。下面是使用步骤: 1. 添加依赖 在 `pom.xml` 文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rocketmq</artifactId> <version>3.1.0</version> </dependency> ``` 2. 配置 RocketMQ 在 `application.yml` 文件中添加以下配置: ```yaml spring: cloud: stream: rocketmq: binder: name-server: ${ROCKETMQ_NAMESRV_ADDR:localhost:9876} producer: group: my-group consumer: group: my-group ``` 其中 `ROCKETMQ_NAMESRV_ADDR` 是 RocketMQ 的 NameServer 地址,`my-group` 是消费者和生产者所属的组名。 3. 定义消息通道 在 Spring Boot 应用程序中定义一个消息通道。可以使用 `@Input` 和 `@Output` 注解来定义通道。例如: ```java public interface MyChannels { String INPUT = "myInput"; String OUTPUT = "myOutput"; @Input(INPUT) SubscribableChannel input(); @Output(OUTPUT) MessageChannel output(); } ``` 4. 使用消息通道 使用 `@EnableBinding` 注解启用绑定,并注入定义的消息通道。例如: ```java @SpringBootApplication @EnableBinding(MyChannels.class) public class Application { private final MyChannels channels; public Application(MyChannels channels) { this.channels = channels; } @Bean public ApplicationRunner runner() { return args -> { channels.output().send(MessageBuilder.withPayload("Hello, World!").build()); }; } @StreamListener(MyChannels.INPUT) public void handle(String message) { System.out.println("Received message: " + message); } public static void main(String[] args) { SpringApplication.run(Application.class, args); } } ``` 在上面的示例中,`runner()` 方法使用 `output()` 方法发送一条消息到 `myOutput` 通道。`@StreamListener` 注解接收 `myInput` 通道的消息,并将其打印到控制台。 这样就可以使用 Spring Cloud Stream 集成 RocketMQ 实现消息驱动的微服务架构了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值