项目实战
定义基础模块
首先引入依赖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
接口中的方法的实现。它负责发送消息到指定的消息通道,并执行一系列的操作:- 首先,对参数进行校验,确保
channelName
和deploy
不为空。 - 然后,检查
channelMap
是否为空,如果为空则抛出异常。 - 接着,根据
channelName
从channelMap
中获取对应的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 的规范
-
常量
TEST_INPUT
和TEST_OUTPUT
:- 这两个常量分别定义了输入通道和输出通道的名称。
-
方法
testInput()
:- 这是一个用于获取测试输入通道的方法。
- 使用
@Input(TEST_INPUT)
注解来标注这个方法,表示这是一个输入通道,名称为TEST_INPUT
。 - 返回类型为
SubscribableChannel
,表示这是一个可订阅的消息通道。
-
方法
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
注解会在应用程序启动时自动配置相关的消息通道,使得应用程序能够与消息中间件进行无缝集成。