Springcloud-Alibaba 〖十二〗Springcloud Stream 整合Rockermq
- PS: github倉庫[倉庫地址](https://github.com/ktoking/springcloud-alibaba)項目都放到裏面了
- 一. 消息總線先放放,感覺現在用不到
- 二. Springcloud Stream
- 沒Rocketmq基礎的同學來這: [來看這裏!!!](https://blog.csdn.net/kingtok/article/details/104212625)之前早已準備好的博客~~
- 三. 新建module cloud-stream-rocketmq-provider8801 消息提供者
- 四. 新建模塊cloud-stream-rabbitmq-consumer8802爲消費者
- Springcloud Stream篇完,本篇使用的是Rocketmq,簡化了MQ底層的操作,配置了一套簡潔版的消息服務~
- 轉載請標註~
PS: github倉庫倉庫地址項目都放到裏面了
強烈建議先去看我的Rocketmq: Rocketmq集羣搭建
一. 消息總線先放放,感覺現在用不到
給大家看看原理
Spring Cloud Bus是用來將分佈式系統的節點與輕量級消息系統鏈接起來的框架,
它整合了Java的事件處理機制和消息中間件的功能。Spring Clud Bus目前支持RabbitMQ和Kafka。
什麼是總線?
在微服務架構的系統中,通常會使用輕量級的消息代理來構建一個共用的消息主題,並讓系統中所有微服務實例都連接上來。由於該主題中產生的消息會被所有實例監聽和消費,所以稱它爲消息總線。在總線上的各個實例,都可以方便的廣播一些需要讓其他連接在該主題上的實例都知道的消息。
基本原理
ConfigClient 實例都監聽MQ中同一個topic(默認是springcloubus),當一個服務刷新數據的時候,它會把這個信息放入到Topic中,這樣其他監聽統一topic的服務就能得到通知,然後去更新自身的配置。
二. Springcloud Stream
這裏頭比較鐵啊,因爲用的是springcloud-alibaba,所以自然肯定要用巴巴的rocketmq啊,而且之前還學過,配過集羣環境與控制檯,那我們就嘗試一下Rocketmq嘻嘻~
沒Rocketmq基礎的同學來這: 來看這裏!!!之前早已準備好的博客~~
stream遵循發佈訂閱模式
三. 新建module cloud-stream-rocketmq-provider8801 消息提供者
3.1 項目結構
3.2 pom
<?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>cloud2020</artifactId>
<groupId>com.aiguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rocketmq-provider8801</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<!--stream-rocketmq-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
3.3 application.yml
server:
port: 8801
spring:
cloud:
stream:
rocketmq:
binder:
namesrv-addr: 公網IP1:9876,公網IP2:9876
# 定義name爲output的binding
bindings:
output: # 定義name爲output的binding
destination: springboot-mq #相當於topic
content-type: application/json
# 定義name爲input的binding
# input1:
# destination: test-topic
# content-type: application/json
# group: test-group
eureka:
client: #客戶端進行eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 #設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 #如果現在超過了5秒的間隔(默認是90秒)
instance-id: send-8801.com #在信息列表時顯示主機名稱
prefer-ip-address: true #訪問的路徑變爲IP地址
3.5 主啓動類
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@EnableEurekaClient
@SpringBootApplication
public class StreamMQMain8801 {
public static void main(String[] args) {
SpringApplication.run(StreamMQMain8801.class,args);
}
}
3.6 業務類
controller層
package com.atguigu.springcloud.controller;
import com.atguigu.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("/sendMessage")
public String sendMessage(){
return messageProvider.send();
}
}
service接口
package com.atguigu.springcloud.service;
public interface IMessageProvider {
public String send();
}
實現類
package com.atguigu.springcloud.service.impl;
import com.atguigu.springcloud.service.IMessageProvider;
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;
@EnableBinding(Source.class)
public class IMessageProviderImpl implements IMessageProvider {
@Resource
private MessageChannel output; //消息發送管道
@Override
public String send() {
String serial = UUID.randomUUID().toString();
output.send(MessageBuilder.withPayload(serial).build());
System.out.println("*****serial: " +serial);
return null;
}
}
3.7 測試
這裏測試類,我們用之前Rocketmq章結用的一個consumer來監聽這個topic下所有tags
也可以不用一下測試類,因爲還要導pom,之後再寫一個8802項目作爲服務消費者
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.4.0</version>
</dependency>
package com.itheima.mq.rocketmq.base.consumer;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext;
import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus;
import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.common.protocol.heartbeat.MessageModel;
import java.util.List;
/**
* 消息的接受者
*/
public class Consumer {
public static void main(String[] args) throws Exception {
//1.創建消費者Consumer,制定消費者組名
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group1");
//2.指定Nameserver地址
consumer.setNamesrvAddr("一號服務器公網IP:9876;二號服務器公網IP:9876");
//3.訂閱主題Topic和Tag
consumer.subscribe("springboot-mq", "*");
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeConcurrentlyContext consumeConcurrentlyContext) {
for (MessageExt messageExt : list) {
String rt=new String(messageExt.getBody());
System.out.println(rt);
}
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
//5.啓動消費者consumer
consumer.start();
}
}
這裏我們訪問服務 http://localhost:8801/sendMessage,這時就會像我們Rocketmq裏發一條消息,我們用consumer就可以實時的監聽到
這裏是打印出了Message所有信息
這裏打印出了剛發送的消息
四. 新建模塊cloud-stream-rabbitmq-consumer8802爲消費者
4.1 pom
<?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>cloud2020</artifactId>
<groupId>com.aiguigu.springcloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-stream-rocketmq-consumer8802</artifactId>
<dependencies>
<!--stream-rocketmq-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rocketmq</artifactId>
<version>0.2.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
4.2 application.yml
server:
port: 8802
spring:
application:
name: rocketmq-consumer
cloud:
stream:
rocketmq:
binder:
namesrv-addr: 一號服務器IP:9876;二號服務器IP:9876
# 定義name爲output的binding
bindings:
# output: # 定義name爲output的binding
# destination: springboot-mq
# content-type: application/json
# 定義name爲input的binding
input:
destination: springboot-mq #消費哪個topic
content-type: application/json
group: group1 #定義消費者組名
eureka:
client: #客戶端進行eureka註冊的配置
service-url:
defaultZone: http://localhost:7001/eureka
instance:
lease-renewal-interval-in-seconds: 2 #設置心跳的時間間隔(默認是30秒)
lease-expiration-duration-in-seconds: 5 #如果現在超過了5秒的間隔(默認是90秒)
instance-id: recive-8802.com #在信息列表時顯示主機名稱
prefer-ip-address: true #訪問的路徑變爲IP地址
4.3 主啓動類
package com.atguigu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class StreamMQmMain8802 {
public static void main(String[] args) {
SpringApplication.run(StreamMQmMain8802.class,args);
}
}
4.4 業務類
controller層
package com.atguigu.springcloud.controller;
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.Component;
@Component
@EnableBinding(Sink.class)
public class ReceiveMessageListenerController {
@Value("${server.port}")
private String serverPort;
@StreamListener(Sink.INPUT)
public void input(Message<String> message){
System.out.println("消費者1號,------->接收到的消息: "+message.getPayload()+"\t port: "+serverPort);
}
}
4.5 測試
我們把7001註冊中心,8801生產者,8802消費者都啓動起來,這時我們去調用8801的方法生成隨機訂單號發給消息隊列,8802立馬監聽到了相同topic下的消息,並把消息打在公屏上
這時候我們rocketmq控制檯也有了相對應的曲線與分析
4.8 yml詳解(非本項目)
消費者
spring:
cloud:
stream:
default-binder: rocketmq
rocketmq:
binder:
name-server: 192.168.1.179:9876
bindings:
#自定義的名稱 對應spring.cloud.stream.bindings.input1
input1:
consumer:
tags: test-tag1 # 訂閱的tag,二級分類
orderly: false # 是否按順序消費
bindings:
#自定義的名稱
input1:
destination: test-topic-user # 訂閱的topic ,一級分類
content-type: application/json
group: test-input-group1 #group
consumer:
concurrency: 20
maxAttempts: 1
生產者
spring:
cloud:
stream:
default-binder: rocketmq
rocketmq:
binder:
#rocketmq地址
name-server: 192.168.0.78:9876
bindings:
#自定義的名稱 對應spring.cloud.stream.bindings.output1
output1:
producer:
group: test-group-user-ouput1
sync: true
#Binding: 包括 Input Binding 和 Output Binding。
#Binding 在消息中間件與應用程序提供的 Provider 和 Consumer 之間提供了一個橋樑,
#實現了開發者只需使用應用程序的 Provider 或 Consumer 生產或消費數據即可,屏蔽了開發者與底層消息中間件的接觸。
bindings:
#自定義的名稱
output1:
destination: test-topic-user # topic(一級分類)
content-type: application/json
4.7 重複消息
微服務應用放置於同一個group中,就能夠保證消息只會被其中一個應用消費一次。
不同的組是可以消費的,同一個組內會發生競爭關係,只有其中 一個可以消費。
就是負載均衡的意思~指定相同組的消費者負載均衡的消費消息