Spring Cloud Stream是一个构建消息驱动微服务的框架。它支持RabbitMQ和Kafka。这里使用RabbitMQ.
官网:https://spring.io/projects/spring-cloud-stream#overview
中文网站:https://m.wang1314.com/doc/webapp/topic/20971999.html
我们要在项目中使用RabbitMQ,首先要有一个完整的RabbitMQ环境,首先搭建一些RabbitMQ环境。
RabbitMQ环境搭建: https://www.cnblogs.com/JustinLau/p/11738511.html,写的很详细。按照这篇文章一步一步配置应该是没问题的。
搭建完成后,访问http://localhost:15672/,如果能看到以下页面就表明搭建成功了。
接下来我们开始撸代码,创建服务rabbitMQProvider9004
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloudstudy</artifactId>
<groupId>com.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitMQProvider9004</artifactId>
<dependencies>
<!-- Spring Cloud Stream RabbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!-- SpringCloud alibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
创建application.yml
server:
port: 9004
spring:
application:
name: stream-rabbitmq-provider #本服务的名称
cloud: #注册到nacos
nacos:
discovery:
server-addr: localhost:8848
stream:
binders: #需要绑定的rabbitmq的服务信息
defaultRabbit: #定义的名称,用于binding整合
type: rabbit #消息组件类型
environment: #环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
output: # 名字是一个通道的名称
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json
binder: defaultRabbit #设置要绑定的消息服务的具体设置
management:
endpoints:
web:
exposure:
include: "*"
创建启动类RabbitMQProviderMain9004
@SpringBootApplication
@EnableDiscoveryClient
public class RabbitMQProviderMain9004 {
public static void main(String[] args) {
SpringApplication.run(RabbitMQProviderMain9004.class,args);
}
}
创建一个service包创建ProviderMessage接口
public interface ProviderMessage {
public void send();
}
在service包下创建impl包创建ProviderMessageImpl类实现ProviderMessage接口
@EnableBinding(Source.class) //定义消息的推送广告
public class ProviderMessageImpl implements ProviderMessage {
@Resource
private MessageChannel output; //消息发送管道
@Override
public void send() {
String uuid = UUID.randomUUID().toString();
output.send(MessageBuilder.withPayload(uuid).build());
System.out.println("9004发送消息: " +uuid);
}
}
创建controller包MessageController类
@RestController
public class MessageController {
@Resource
ProviderMessage providerMessage;
@GetMapping(value = "/message/send")
public String send(){
providerMessage.send();
return "发送成功!";
}
}
现在创建消息消费服务rabbitMQConsumer9005
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>cloudstudy</artifactId>
<groupId>com.study</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>rabbitMQConsumer9005</artifactId>
<dependencies>
<!-- Spring Cloud Stream RabbitMQ-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<!-- SpringCloud alibaba nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.hmy.springcloud</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
application.yml(和9004有不同,注意一下)
server:
port: 9005
spring:
application:
name: stream-rabbitmq-consumer #本服务的名称
cloud: #注册到nacos
nacos:
discovery:
server-addr: localhost:8848
stream:
binders: #需要绑定的rabbitmq的服务信息
defaultRabbit: #定义的名称,用于binding整合
type: rabbit #消息组件类型
environment: #环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: # 服务的整合处理
input: # 名字是一个通道的名称 注意这里和生产消息不同
destination: studyExchange # 表示要使用的Exchange名称定义
content-type: application/json # 设置消息类型,本次为json
binder: defaultRabbit #设置要绑定的消息服务的具体设置
management:
endpoints:
web:
exposure:
include: "*"
主启动类RabbitConsumer9005
@SpringBootApplication
@EnableDiscoveryClient
public class RabbitConsumer9005 {
public static void main(String[] args) {
SpringApplication.run(RabbitConsumer9005.class,args);
}
}
创建ConsumerController
@Component
@EnableBinding(Sink.class)
public class ConsumerController {
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message){
System.out.println("9005收到消息:"+message.getPayload()+"\t port:"+serverPort);
}
}
依次启动9004,9005,访问localhost:9004/message/send,打开idea控制台
我们思考两个问题,1、我们在做集群服务的时候,如果接收消息的服务有两个,此时消息服务器发了一个消息,会被两个服务都消费。例如,订单服务发送了一条消息,两个库存服务都消费了这个消息,都对库存进行-1操作,这就出了问题。2、消息服务发了消息,但是消费服务由于一些原因停止了服务,当它再次启动的时候,无法接收到消息了。
对于以上两个问题解决办法很简单,分组就完事了。
创建服务rabbitMQConsumer9006,除了把端口号改成9006,其他与9005一样。启动9004,9005,9006
访问localhost:9004/message/send
打开控制台,查看9004,9005,9006的控制台输出
两个服务都收到了消息,现在我们来解决这个问题,修改9005和9006的application.yml文件
两个服务添加一样的分组名。启动服务,发送消息,会发现9005和9006会轮询接收消息,这样就可以避免消息重复消费。
现在关闭9005和9006,关闭服务后,9004发送消息,把9006的分组属性去掉,再次启动9005和9006
此时会发现,9005启动后收到了消息,9006没有收到。
使用Spring Cloud Alibaba创建springcloud项目-6.Sentinel