1、什麼是Spring Cloud Stream
Spring Cloud Stream 是一個用來爲微服務應用構建消息驅動能力的框架。它可以基於Spring Boot 來創建獨立的,可用於生產的Spring 應用程序。他通過使用Spring Integration來連接消息代理中間件以實現消息事件驅動。Spring Cloud Stream 爲一些供應商的消息中間件產品提供了個性化的自動化配置實現,引用了發佈-訂閱、消費組、分區的三個核心概念。目前僅支持RabbitMQ、Kafka。
什麼是Spring Integration ? Integration 集成
企業應用集成(EAI)是集成應用之間數據和服務的一種應用技術。四種集成風格:
1. 文件傳輸:兩個系統生成文件,文件的有效負載就是由另一個系統處理的消息。該類風格的例子之一是針對文件輪詢目錄或FTP目錄,並處理該文件。
2. 共享數據庫:兩個系統查詢同一個數據庫以獲取要傳遞的數據。一個例子是你部署了兩個EAR應用,它們的實體類(JPA、Hibernate等)共用同一個表。
3. 遠程過程調用:兩個系統都暴露另一個能調用的服務。該類例子有EJB服務,或SOAP和REST服務。
4. 消息:兩個系統連接到一個公用的消息系統,互相交換數據,並利用消息調用行爲。該風格的例子就是衆所周知的中心輻射式的(hub-and-spoke)JMS架構。
Spring Integration作爲一種企業級集成框架,遵從現代經典書籍《企業集成模式》,爲開發者提供了一種便捷的實現模式。Spring Integration構建在Spring控制反轉設計模式之上,抽象了消息源和目標,利用消息傳送和消息操作來集成應用環境下的各種組件。消息和集成關注點都被框架處理,所以業務組件能更好地與基礎設施隔離,從而降低開發者所要面對的複雜的集成職責。
模型
Spring Cloud Stream由一箇中間件中立的核組成。應用通過Spring Cloud Stream插入的input和output通道與外界交流。通道通過指定中間件的Binder實現與外部代理連接。
業務開發者不再關注具體消息中間件,只需關注Binder對應用程序提供的抽象概念來使用消息中間件實現業務即可。
綁定器
通過定義綁定器作爲中間層,實現了應用程序與消息中間件細節之間的隔離。通過嚮應用程序暴露統一的Channel通過,是的應用程序不需要再考慮各種不同的消息中間件的實現。當需要升級消息中間件,或者是更換其他消息中間件產品時,我們需要做的就是更換對應的Binder綁定器而不需要修改任何應用邏輯 。
目前只提供了RabbitMQ和Kafka的Binder實現
消費組
由於發佈-訂閱模型使得共享主題的應用之間連接更簡便,創建給定應用的不同實例來進行彈性擴張的能力也同樣重要。如果存在多個應用實例,那麼同一應用的額不同實例便會成爲相互競爭的消費者,其中應該只有一個實例處理給定消息。
Spring Cloud Stream通過消費者組的概念給這種情況進行建模。每一個單獨的消費者可以使用spring.cloud.stream.bindings.input.group屬性來指定一個組名字。下圖中展示的消費者們,這一屬性被設置爲spring.cloud.stream.bindings.input.group=hdfsWrite或者spring.cloud.stream.bindings.input.group=average。
所有訂閱給定目標的組都會收到發佈消息的一個拷貝,但是每一個組內只有一個成員會收到該消息。默認情況下,如果沒有指定組,Spring Cloud Stream 會將該應用指定給一個匿名的獨立的單成員消費者組,後者與所有其他組都處於一個發佈-訂閱關係中。
消息分區
Spring Cloud Stream對給定應用的多個實例之間分隔數據予以支持。在分隔方案中,物理交流媒介(如:代理主題)被視爲分隔成了多個片(partitions)。一個或者多個生產者應用實例給多個消費者應用實例發送消息並確保相同特徵的數據被同一消費者實例處理。
Spring Cloud Stream對分割的進程實例實現進行了抽象。使得Spring Cloud Stream 爲不具備分區功能的消息中間件(RabbitMQ)也增加了分區功能擴展。
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
</dependency>
</dependencies>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
接收者接口
import org.springframework.cloud.stream.annotation.Input;
import org.springframework.messaging.SubscribableChannel;
public interface Sink {
String INPUT="input";
@Input(Sink.INPUT)
SubscribableChannel input();
}
它通過@Input註解綁定了一個名爲input的通道。除了Sink之外,Spring Cloud Stream還默認實現了綁定output通道的Source接口,還有結合了Sink和Source的Processor接口,實際使用時我們也可以自己通過@Input和@Output註解來定義綁定消息通道的接口。當我們需要爲@EnableBinding指定多個接口來綁定消息通道的時候,可以這樣定義:@EnableBinding(value = {Sink.class, Source.class})。
接受者實現
@EnableBinding(Sink.class) //綁定@input註解的接口 實現消息通道的綁定
public class SinkReceiver {
@StreamListener(Sink.INPUT)////將被修飾的方法註冊爲消息中間件上數據流的事件監聽器,
public void receive(Object object){
System.out.println(object+" .........");
}
}
生產者接口
@Component
public interface SinkSender {
String OUTPUT = "input";
@Output(SinkSender.OUTPUT)
MessageChannel output();
}
生產者實現
@RunWith(SpringRunner.class)
@EnableBinding(value = {SinkSender.class})
public class SinkApplicationTests {
@Autowired
private SinkSender sinkSender;
@org.junit.Test
public void sindMessage(){
sinkSender.output().send(MessageBuilder.withPayload("啥").build());
}
}
先啓動消費者 在啓動生產者
Spring integration支持
@ServiceActivator 和 @InboundChannelAdapter
@ServiceActivator註解 和 @StreamListener 都實現了對消息的監聽,ServiceActivator 沒有內置消息轉換,需要自己實現轉換
@StreamListener 不需要自己實現,只需要在配置文件增加spring.cloud.stream.bindings.input.content-type=application/json 屬性(默認支持json,json格式的可以不用配置)
詳細內容可運行demo:metadata-rabbit-stream-integration-consumer和metadata-rabbit-stream-integration-server
生產者
@RunWith(SpringRunner.class)
@EnableBinding(value = {SinkSender.class})
public class SinkApplicationTests {
@Autowired
private SinkSender sinkSender;
@org.junit.Test
public void sindMessage(){
Student student=new Student();
student.setId(1);
student.setName("tom");
sinkSender.output().send(MessageBuilder.withPayload(student).build());
}
}
消費者
@EnableBinding({Sink.class}) //綁定@input註解的接口 實現消息通道的綁定
public class SinkReceiver {
@StreamListener(Sink.INPUT)////將被修飾的方法註冊爲消息中間件上數據流的事件監聽器,
public void receive(Student object){
System.out.println(object+" .........");
}
}