SpringCloud 進階: 消息驅動(入門)Spring Cloud Stream【Greenwich.SR3】

?我的博客:程序員笑笑生,歡迎瀏覽博客!

?上一章 SpringCloud 基礎教程(十二)-Zipkin分布式鏈路追蹤系統搭建當中,我們使用Zipkin搭建完整的實時數據追蹤系統。本章開始我們將進入Spring Cloud的更高階的內容部分,首先從消息驅動Spring Cloud Stream開始。

前言

?消息驅動,顧明思議,在企業級應用中,消息中間件經常用于處理非同步場景、消息通知、應用解耦等。常用的有RabbitMq、kafka、Redis等消息隊列等。Spring Cloud Stream是一個構建事件消息驅動的微服務框架,提供了一個靈活的編程模型。并基于Spring的基礎之上,支持發布-訂閱模型、消費者分組、數據分片等功能。

一、Stream 應用模型

file
  • Middleware: 消息中間件,如RabbitMq等
  • Binder:可以認為是適配器,用來將Stream與中間連接起來的,不同的Binder對應不同的中間件,需要我們配置
  • Application Core:由Stream封裝的消息機制,很少情況下自定義開發
  • inputs:輸入,可以自定義開發
  • outputs:輸出,可以自定義開發

接下來快速開始,主要就是針對以上幾個組件進行不同的配置。

二、快速開始

?接下來,我們以RabbitMQ為例(消息隊列的環境搭建整這里不做過多的介紹,本章以Stream為主),新建2個Maven工程,分別當做消息生產者(server-receiver)、消息生產者(server-sender),在2個項目中引入Stream依賴和Stream對RabbitMq的依賴,在生產者單獨的添加web的依賴,為了能夠通過HTTP調用發送信息:

<dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
<dependency>
       <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-stream</artifactId>
</dependency>

2.1 server-receiver消費者

?啟動主類:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
/**
 * @EnableBinding 表示告訴當前應用,增加消息通道的監聽功能
 * 監聽Sink類中名為input的輸入通道:
 */
@SpringBootApplication
@EnableBinding(Sink.class)
public class ReceiverApplication {

    public static void main(String[] args) {
        SpringApplication.run(ReceiverApplication.class, args);
    }
    /**
     * 監聽rabbitmq的消息,具體什么隊列,什么topic,通過配置信息application獲取
     *
     * @param msg
     */
    @StreamListener(Sink.INPUT)
    public void reader(String msg) {
        System.out.print("receiver {}:" + msg);
    }
}

application.yml配置:

spring:
  cloud:
    stream:
      bindings:
         input:
            destination: mytopic
            binder: defaultRabbit
      binders:
         defaultRabbit:
             type: rabbit
             environment:
                spring:
                 rabbitmq:
                     host: localhost
                     port: 5672
server:
  port: 8081

?具體配置詳解,spring.cloud.stream為前綴:

bindings配置:

  • input:表示channelName,這里為什么是input,是因為啟動類中@EnableBinding(Sink.class)注解當中配置Sink接口,該接口中默認定義了channelName的名稱,當然我們也可以自己寫Sink接口
  • destination:消息中間件的Topic
  • binder:當前bingding綁定的對應的適配器,該實例表示適配rabbitmq,名稱默認為defaultRabbit,可以自定義,接著需要配置該名稱對應的類型,環境信息等

binders配置:

  • defaultRabbit:binder配置的適配器的名稱,和spring.cloud.stream.bindings.input.binder值一樣
  • environment:表示當前binder對應的配置信息

2.2 生產者server-sender

?SenderApplication啟動類,添加@EnableBinding注解:

import com.microservice.stream.controller.SenderSource;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.annotation.EnableBinding;
/**
 * @EnableBinding(SenderSource.class) 表示監聽Stream通道功能
 * 
 * SenderSource為自定義的通道接口
 * 
 */
@SpringBootApplication
@EnableBinding(SenderSource.class)
public class SenderApplication {
   
    public static void main(String[] args) {
        SpringApplication.run(SenderApplication.class,args);

    }
}

?自定義SenderSource接口,參考org.springframework.cloud.stream.messaging.Source,將channel的名稱改成和消費者的Sink的channel名稱一樣。

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

public interface SenderSource {
    /**
     * Name of the output channel.
     */
    String OUTPUT = "input";
    /**
     * @return output channel
     */
    @Output(SenderSource.OUTPUT)
    MessageChannel output();
}

?編寫控制器,通過HTTP發送消息:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SenderController {
    @Autowired
    SenderSource source;
    
    @RequestMapping("/send")
    public String sender(String msg) {
        source.output().send(MessageBuilder.withPayload(msg).build());
        return "ok";
    }

}

?applicaiton.yml配置,配置和消費者的配置一樣

spring:
  cloud:
    stream:
      bindings:
         input:
            destination: mytopic
            binder: defaultRabbit
      binders:
         defaultRabbit:
             type: rabbit
             environment:
                spring:
                 rabbitmq:
                     host: localhost
                     port: 5672
server:
  port: 8081                     

2.3 啟動接受者和消費者,發送消息

?首先啟動消費者,看啟動日志,我們看到程序聲明了一個名稱為:mytopic.anonymous.88A97a5vQ9Ox07GnNBlKYQ的隊列,并且綁定了mytopic 主題,創建了一個連上rabbit的連接:

file

我們看看rabbit的web頁面隊列列表中就有了新增了一個隊列,并且綁定了mytopic主題:

file

然后再啟動生產者server-sender,在啟動日志中我們也看到了應用創建了到對應的消息隊列的連接:

file

接下來我們通過HTTP發送信息:http://localhost:8081/send/?msg=test,在服務消費者的日志中,監聽到了對應的消息:

file

通過以上的簡單的實例,我們體驗了Spring Cloud Stream在提供消息驅動服務方面非常的方便。

三、代碼分析

3.1 @EnableBinding注解

?@EnableBinding表示告訴應用增加了通道監聽功能,可以是一個或者多個,可以傳入Sink和Source類,Sink和Souce可以自定義

3.2 Sink和Soure

?我們首先看看Sink類和Source類,

Sink

/**
 * Bindable interface with one input channel.
 */
public interface Sink {

    /**
     * Input channel name.
     */
    String INPUT = "input";

    /**
     * @return input channel.
     */
    @Input(Sink.INPUT)
    SubscribableChannel input();

}

Source

package org.springframework.cloud.stream.messaging;

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

public interface Source {

    /**
     * Name of the output channel.
     */
    String OUTPUT = "output";

    /**
     * @return output channel
     */
    @Output(Source.OUTPUT)
    MessageChannel output();

}

?Sink和Source一樣是一個接口類型, INPUT、OUTPUT表示channel名稱,@Input、@Output表示注入參數為對應的channel名稱,在我們的上文中我們自定義了SenderSource類型的接口,為了和Sink的channel名稱一樣。

  • Sink:單一的輸入通道
  • Source:單一的輸出通道

?Spring會為每一個標注了@Output,@Input的管道接口生成一個實現類

3.3 Spring-messaging的抽象

?在Sink和source的接口中,我們注意到了MessageChannel、SubscribableChannel類,在spring框架中,spring-message模塊對消息處理的抽象類:

對象 說明
Message 消息
MessageHandler 處理消息的單元
MessageChannel 發送/接受傳輸消息的信道,單項的
SubscribableChannel 繼承MessageChannel,傳送消息到所有的訂閱者
ExecutorSubscribableChannel 繼承SubscribableChannel,異步線程池傳輸消息

四、配置文件

??配置文件的格式如下,<>表示我們可以自定義:

spring:
  cloud:
    stream:
      bindings:
         <channel-name>:   #channel名稱
            destination: mytopic  # 發布-訂閱模型的消息主題topic
            binder: defaultRabbit  #binder(適配器的名稱)
      binders:
         <binder-name>:  # 根據binder配置一樣的名稱
             type: rabbit  # 中間件的類型
             environment:  # 中間件實例的環境
                spring:
                 rabbitmq:
                     host: localhost
                     port: 5672

?我們可以定義多個binding,分別為binding綁定相同或不同的Binder

總結

?本章我們初步的介紹了Spring Cloud Stream,通過對Steam的應用模型一節通過消息生產者和消費者模型實現了簡單的發布-訂閱的模型,對Stream有了一些了解,Steram的功能遠不止于此。在后期的介紹中,我還將繼續深入的介紹Stream更多的內容。

file
file
file

SpringCloud基礎教程(一)-微服務與SpringCloud

SpringCloud基礎教程(二)-服務發現 Eureka

SpringCloud基礎教程(三)-Eureka進階

SpringCloud 基礎教程(四)-配置中心入門

SpringCloud基礎教程(五)-配置中心熱生效和高可用

SpringCloud 基礎教程(六)-負載均衡Ribbon

SpringCloud 基礎教程(七)-Feign聲明式服務調用

SpringCloud 基礎教程(八)-Hystrix熔斷器(上)

SpringCloud 基礎教程(九)-Hystrix服務監控(下)

SpringCloud 基礎教程(十)-Zull服務網關

SpringCloud 基礎教程(十一)- Sleuth 調用鏈追蹤簡介

SpringCloud 基礎教程(十二)-Zipkin 分布式鏈路追蹤系統搭建

SpringCloud 進階: 消息驅動(入門) Spring Cloud Stream【Greenwich.SR3】

更多精彩內容,請期待...

本文由博客一文多發平臺 OpenWrite 發布!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容