<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-stream-rabbitartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>com.hry.springcloudgroupId>
<artifactId>cloud-api-commonsartifactId>
<version>${project.version}version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<scope>runtimescope>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
server:
port: 8801
spring:
application:
name: cloud-stream-provider
cloud:
stream:
binders: #此处配置要绑定的rabbitmq的服务信息
defaultRabbit: #表示定义的名称,用于binding集合
type: rabbit #消息组件类型
environment: #设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: #服务的整合处理
output:
destination: studyExchange #表示要使用的Exchange名称定义
content-type: application/json #设置消息类型,本次为json,文本则设置 text/plain
binder: defaultRabbit #设置要绑定的消息服务的具体位置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 #设置心跳的时间间隔(默认30s)
lease-expiration-duration-in-seconds: 5 #默认90s
instance-id: send-8801.com #在信息列表时显示主机名称
prefer-ip-address: true #访问的路径变为IP地址
package com.hry.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamMQMain8801 {
public static void main(String[] args) {
SpringApplication.run(StreamMQMain8801.class, args);
}
}
新建service包,在包中新建接口
package com.hry.springcloud.service;
public interface IMessageProvider {
public String send();
}
在Impl包下新建实现类
package com.hry.springcloud.service.Impl;
import cn.hutool.core.map.MapBuilder;
import com.hry.springcloud.service.IMessageProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.support.MessageBuilder;
import javax.annotation.Resource;
import java.util.UUID;
/**
* 定义消息的推送管道
* 为什么是Source 可以参考前面知识点第三张图 Source--Sink
*/
@EnableBinding(Source.class)
@Slf4j
public class MessageProviderImpl implements IMessageProvider {
/**
* 消息发送管道
*/
@Resource
private MessageChannel output;
@Override
public String send() {
String serial = UUID.randomUUID().toString();
output.send(MessageBuilder.withPayload(serial).build());
log.info("*****serial: "+serial);
return null;
}
}
controller
package com.hry.springcloud.controller;
import com.hry.springcloud.service.IMessageProvider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class SendMessageController {
@Resource
private IMessageProvider messageProvider;
@GetMapping(value = "/send")
public String sendMessage(){
return messageProvider.send();
}
}
启动7001和8801,启动RabbitMQ
打开8801,多刷新几次 然后看控制台打印的日志
15672上的波峰也会变化
与8801一样,直接复制8801的dependencies
server:
port: 8802
spring:
application:
name: cloud-stream-consumer
cloud:
stream:
binders: #此处配置要绑定的rabbitmq的服务信息
defaultRabbit: #表示定义的名称,用于binding集合
type: rabbit #消息组件类型
environment: #设置rabbitmq的相关的环境配置
spring:
rabbitmq:
host: localhost
port: 5672
username: guest
password: guest
bindings: #服务的整合处理
input:
destination: studyExchange #表示要使用的Exchange名称定义
content-type: application/json #设置消息类型,本次为json,文本则设置 text/plain
binder: defaultRabbit #设置要绑定的消息服务的具体位置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 #设置心跳的时间间隔(默认30s)
lease-expiration-duration-in-seconds: 5 #默认90s
instance-id: receive-8802.com #在信息列表时显示主机名称
prefer-ip-address: true #访问的路径变为IP地址
package com.hry.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class StreamMain8802 {
public static void main(String[] args) {
SpringApplication.run(StreamMain8802.class, args);
}
}
package com.hry.springcloud;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.messaging.Message;
import org.springframework.stereotype.Controller;
@Controller
@Slf4j
@EnableBinding(Sink.class)
public class controllerRecvMsgListenerController {
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message){
log.info("消费者1号,端口号"+serverPort+"/t接收到的消息:"+message.getPayload());
}
}
8801发送,8802接收
刷新几遍8801/send
收发一致 没什么问题。
与8802一样,略过
启动后,使用8801发送三条消息
发现8802和8803都收到了消息,一个订单同时被两个服务获取到会造成数据错误,属于重复消费,如果想要只消费一次那就把他们放到同一个组
group: AAAAA
8003同理,这里改成BBBBB。
然后看大组名已经从之前长长的一串变成我们自己改的5个A和5个B了。
但这样跟之前没区别,还是两个不同的分组。
这时只需要把8803的yml中的group也改成 AAAAA它俩就是在一组中了。
重启8803,查看,这时候小问号就问了,怎么还是两个?
不急分别点进去看一看
AAAAA已经是两个了,5个B还在是因为历史记录,实际上里边已经没有Consumer啦
8802 | 8803 |
---|---|
消费者1号,端口号8802 接收到的消息:349a6ef7-d887-4188-9992-5e53ae523a54 | 消费者2号,端口号8803 接收到的消息:c0c66958-c0e3-4073-8dee-7220d912630a |
停掉8802和8803,将8802yml中的group去掉,8803yml不变。
当使用8801发送消息后,启动8802和8803会发现8802没有接收到消息,而8803收到了消息,证明了有了group配置,即使接收方当时停机,启动后依旧能接收到消息。
使用8801发送两条消息。
启动8802和8803
8802由于移除了group配置啥也没收到
8803开机后成功收到消息