SpringCloudStream極簡教程

Naylor發表於2024-12-06

簡介

Spring Cloud Stream 是一個輕量級訊息驅動微服務框架,旨在簡化與訊息中介軟體(如 Kafka、RabbitMQ 等)的整合,支援訊息的釋出和訂閱模式。它提供了一種基於 Spring 程式設計模型的方式(即自動依賴注入和強調透過註解來完成功能的封裝),使得構建可擴充套件和靈活的訊息驅動應用變得更加簡單。

特點

  • 訊息中介軟體支援:Spring Cloud Stream 支援多種訊息中介軟體,包括 Kafka、RabbitMQ 等,使用者可以透過簡單的配置切換不同的訊息系統而不需修改業務邏輯程式碼。
  • 繫結模型:Spring Cloud Stream 透過“繫結”抽象層來簡化與訊息中介軟體的互動。開發者不需要直接處理底層的訊息中介軟體,而是透過定義“繫結器”來與訊息源(如 Kafka、RabbitMQ)進行通訊。
  • 訊息驅動:提供了事件驅動和流處理的支援。
  • 簡化配置:透過 Spring Boot 的自動配置,Spring Cloud Stream 可以透過簡單的屬性配置來進行訊息系統的連線和訊息傳遞。
  • 可擴充套件性:Spring Cloud Stream 支援開發者使用自定義的訊息轉換器、處理器等元件,使得訊息傳遞過程能夠根據具體業務需求進行靈活定製。
  • 與 Spring Cloud 整合:在 Spring.io 中是SpringCloud下的頂級專案,可以與SpringCloud其它專案無縫整合,適用於微服務架構。

核心模組

  • Binder:用於實現訊息系統的具體接入,例如 Kafka、RabbitMQ 等。
  • Channel:訊息的通道,透過 @StreamListener 註解來監聽通道,接收和處理訊息。訊息生產者和消費者都是透過Channel來處理訊息的。
  • Producer & Consumer:生產者和消費者,分別負責訊息的釋出和訂閱。Spring Cloud Stream 提供了註解 @Output 和 @Input 來標註訊息通道的生產與消費。

最佳實踐

pom


<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.7.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2021.0.6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring-boot.version}</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        <version>2021.0.6.2</version>
    </dependency>
    <!-- SpringCloud Alibaba Nacos Config -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        <version>2021.0.6.2</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-stream-binder-kafka</artifactId>
    </dependency>
</dependencies>


  • 核心依賴:spring-cloud-stream-binder-kafka
  • 其中已經包含了 spring-kafka 這個依賴,無需重複引入
  • 從其依賴關係來看,SpringCloudStream 的實現引用了 SpringIntegration 這個框架,這也是一個比較有趣的框架,是Spring的頂級框架,感興趣的可以參看 SpringIntegration漫談 瞭解 SpringIntegration 框架的設計立場和實現思路。

yml


spring:
  kafka:
    consumer:
      max-poll-records: 50
      bootstrap-servers: 192.168.1.92:9092


  • max-poll-records:指定消費者每次從 Kafka 拉取(poll)時能夠獲取的最大訊息數量。
  • bootstrap-servers:kafka的server端的連線地址。注意需要將kafka-server 的 server.properties 配置檔案中的 listeners=PRIVATE://0.0.0.0:9092 並且 advertised.listeners=PRIVATE://192.168.1.92:9092 ,否則無法對外提供服務。

定義訊息通道


import org.springframework.cloud.stream.annotation.Input;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.SubscribableChannel;


public interface AircraftChannel {

    /**
     * kafka topic  名稱
     */
    String TOPIC = KAFKA_TOPIC_NGH_AIRCRAFT;
    
    /**
     * 定義消費者接收訊息的通道
     * @return
     */
    @Input(AircraftChannel.TOPIC)
    SubscribableChannel input();
    
    /**
     * 定義生產者傳送訊息的通道
     * @return
     */
    @Output(AircraftChannel.TOPIC)
    MessageChannel output();
}


  • @Input: 使用input註解指定此方法來處理訊息的接收
  • @Output:使用output註解指定此方法來處理訊息的傳送
  • 一個頻道中可以定義多個input和output

定義訊息生產者


import com.nghsmart.nghaircraft.channel.AircraftChannel;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.messaging.support.MessageBuilder;

@AllArgsConstructor
@Slf4j
@EnableBinding(AircraftChannel.class)
public class AircraftProducer {

    private final AircraftChannel aircraftChannel;
    
    public void sendMessage(String message) {
        boolean send = aircraftChannel.output().send(MessageBuilder.withPayload(message).build());
        log.info("send message: {}", message);
    }
}


  • EnableBinding:此註解修飾的類會被Spring容器管理起來,其匯入了@Configuration註解。
  • EnableBinding 註解為 AircraftChannel.class 中的介面建立實現類,並透過Spring的自動配置,實現類會對接kafka的adapter,這樣就實現了通道和kafkaServer的繫結
  • send:透過注入頻道並呼叫頻道中output處理器的send方法將訊息傳送到kafakServer中的特定topic,即AircraftChannel.TOPIC

定義訊息消費者


import com.nghsmart.nghaircraft.channel.AircraftChannel;
import com.nghsmart.nghaircraft.config.RedisTemplateGeneric;
import com.nghsmart.nghaircraft.constant.RedisKeyEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.messaging.Message;

@Slf4j
@AllArgsConstructor
@EnableBinding(AircraftChannel.class)
public class AircraftConsumer {

    @StreamListener(AircraftChannel.TOPIC)
    public void receiveMessage(Message<String> message) {
        try {
            log.debug("AircraftConsumer_Received_message: {}", message.getPayload());
            //TODO 解析資料
       
        } catch (Exception e) {
            log.error("AircraftConsumer_error,msg={}", e.getMessage());
            e.printStackTrace();
        }
    }
}


  • EnableBinding:此註解修飾的類會被Spring容器管理起來,其匯入了@Configuration註解。
  • EnableBinding 註解為 AircraftChannel.class 中的介面建立實現類,並透過Spring的自動配置,實現類會對接kafka的adapter,這樣就實現了通道和kafkaServer的繫結
  • StreamListener:透過StreamListener註解為AircraftChannel.TOPIC這個topic建立監聽,當kafkaAdapter接收到訊息後,將觸發回撥,呼叫receiveMessage方法處理訊息。

定義Http介面

透過請求介面,傳送訊息到 kafka



import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/test")
public class TestController {

    private final AircraftProducer aircraftProducer;
    
    @GetMapping("/test1")
    public String test1() {
        aircraftProducer.sendMessage("test1");
        return "test1";
    }
}


  • 新建一個RESTFful介面用於測試訊息的傳送
  • 透過注入AircraftProducer,呼叫其sendMessage 方法傳送訊息
  • 訊息傳送出去之後,會被AircraftConsumer監聽到,並回撥到receiveMessage,可以透過觀察log,檢視訊息的整個生命週期流轉。

總結

本文介紹了 SpringCloudStream 這個框架的作用和相關生態,並編寫了相應的程式碼示例作為 最佳實踐 參考,程式碼示例會上傳到我的程式碼倉庫 SpringBoot漫談 中(見引用),歡迎大家瀏覽、學習、交流。

公眾號: TechnologyRamble,歡迎大家關注!!!

引用

  • https://spring.io/projects/spring-cloud-stream#overview
  • https://gitee.com/naylor_personal/ramble-spring-boot

相關文章