整合資料

本指南將引導您使用 Spring Integration 建立一個簡單的應用程式,該應用程式從 RSS Feed (Spring Blog) 檢索資料、處理資料,然後將其寫入檔案。 本指南使用傳統的 Spring Integration XML 設定。 其他指南展示如何使用 Java 設定和 DSL(包含和不包含 Lambda 運算式)。

您將建立的內容

您將使用傳統 XML 設定,透過 Spring Integration 建立一個流程。

您需要的東西

如何完成本指南

與大多數 Spring 入門指南一樣,您可以從頭開始並完成每個步驟,或者您可以跳過您已經熟悉的基礎設定步驟。 無論哪種方式,您最終都會得到可運作的程式碼。

若要從頭開始,請前往 從 Spring Initializr 開始

若要跳過基礎,請執行以下操作

當您完成時,您可以將您的結果與 gs-integration/complete 中的程式碼進行比較。

從 Spring Initializr 開始

您可以使用這個 預先初始化的專案,然後點擊 Generate 來下載 ZIP 檔案。 此專案已設定為符合本教學課程中的範例。

手動初始化專案

  1. 導覽至 https://start.spring.io。 此服務會提取應用程式所需的所有依賴項,並為您完成大部分設定。

  2. 選擇 Gradle 或 Maven 以及您要使用的語言。 本指南假設您選擇 Java。

  3. 點擊Dependencies,然後選擇Spring Integration

  4. 點擊Generate

  5. 下載產生的 ZIP 檔案,這是使用您的選擇設定的網站應用程式的封存檔。

如果您的 IDE 具有 Spring Initializr 整合,您可以從您的 IDE 完成此程序。
您也可以從 Github 分叉專案,並在您的 IDE 或其他編輯器中開啟它。

新增至組建檔案

對於這個範例,您需要新增兩個依賴項

  • spring-integration-feed

  • spring-integration-file

以下清單顯示了最終的 pom.xml 檔案

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.3.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>integration-complete</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>integration-complete</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>17</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-integration</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.integration</groupId>
			<artifactId>spring-integration-feed</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.integration</groupId>
			<artifactId>spring-integration-file</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.integration</groupId>
			<artifactId>spring-integration-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

以下清單顯示了最終的 build.gradle 檔案

plugins {
	id 'org.springframework.boot' version '3.3.0'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-integration'
	implementation 'org.springframework.integration:spring-integration-feed'
	implementation 'org.springframework.integration:spring-integration-file'
	testImplementation('org.springframework.boot:spring-boot-starter-test')
	testImplementation 'org.springframework.integration:spring-integration-test'
}

test {
	useJUnitPlatform()
}

定義整合流程

對於本指南的範例應用程式,您將定義一個 Spring Integration 流程,該流程

  • 從 spring.io 的 RSS feed 讀取部落格文章。

  • 將它們轉換為易於閱讀的 String,包含文章標題和文章的 URL。

  • 將該 String 附加到檔案結尾 (/tmp/si/SpringBlog)。

要定義整合流程,您可以建立一個 Spring XML 設定,其中包含 Spring Integration XML 命名空間中的少量元素。 具體來說,對於所需的整合流程,您可以使用以下 Spring Integration 命名空間中的元素:core、feed 和 file。 (取得最後兩個是我們必須修改 Spring Initializr 提供的組建檔案的原因。)

以下 XML 設定檔(來自 src/main/resources/integration/integration.xml)定義了整合流程

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:int="http://www.springframework.org/schema/integration"
	xmlns:file="http://www.springframework.org/schema/integration/file"
	xmlns:feed="http://www.springframework.org/schema/integration/feed"
	xsi:schemaLocation="http://www.springframework.org/schema/integration/feed https://www.springframework.org/schema/integration/feed/spring-integration-feed.xsd
		http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/integration/file https://www.springframework.org/schema/integration/file/spring-integration-file.xsd
		http://www.springframework.org/schema/integration https://www.springframework.org/schema/integration/spring-integration.xsd">

    <feed:inbound-channel-adapter id="news" url="https://spring.dev.org.tw/blog.atom" auto-startup="${auto.startup:true}">
        <int:poller fixed-rate="5000"/>
    </feed:inbound-channel-adapter>

    <int:transformer
            input-channel="news"
            expression="payload.title + ' @ ' + payload.link + '#{systemProperties['line.separator']}'"
            output-channel="file"/>

    <file:outbound-channel-adapter id="file"
            mode="APPEND"
            charset="UTF-8"
            directory="/tmp/si"
            filename-generator-expression="'${feed.file.name:SpringBlog}'"/>

</beans>

這裡使用了三個整合元素

  • <feed:inbound-channel-adapter>:一個入站适配器,它检索帖子,每次轮询一个。如此处配置的,它每五秒轮询一次。这些帖子被放置到一个名为 news 的频道中(对应于适配器的 ID)。

  • <int:transformer>:转换 news 频道中的条目(com.rometools.rome.feed.synd.SyndEntry),提取条目的标题 (payload.title) 和链接 (payload.link),并将它们连接成一个可读的 String(并添加一个换行符)。然后,该 String 被发送到名为 file 的输出频道。

  • <file:outbound-channel-adapter>:一个出站频道适配器,它将其频道(名为 file)的内容写入文件。具体来说,如此处配置的,它将 file 频道中的任何内容附加到 /tmp/si/SpringBlog 的文件中。

下图显示了这个简单的流程

A flow that reads RSS feed entries

暂时忽略 auto-startup 属性。我们稍后在讨论测试时会重新讨论它。现在,请注意默认情况下它是 true,这意味着帖子在应用程序启动时会被获取。另请注意 filename-generator-expression 中的属性占位符。这意味着默认值为 SpringBlog,但可以通过属性覆盖。

使應用程式可執行

雖然在較大的應用程式(甚至可能是網站應用程式)中設定 Spring Integration 流程很常見,但沒有理由不能在更簡單的獨立應用程式中定義它。 這就是您接下來要做的事情:建立一個主類別,啟動整合流程,並宣告少量的 Bean 來支援整合流程。 您還會將應用程式建置為獨立的可執行 JAR 檔案。 我們使用 Spring Boot 的 @SpringBootApplication 註釋來建立應用程式環境。 由於本指南使用 XML 命名空間來進行整合流程,因此您必須使用 @ImportResource 註釋將其載入到應用程式環境中。 以下清單(來自 src/main/java/com/example/integration/IntegrationApplication.java)顯示了應用程式檔案

package com.example.integration;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ImportResource;

@SpringBootApplication
@ImportResource("/integration/integration.xml")
public class IntegrationApplication {
  public static void main(String[] args) throws Exception {
    ConfigurableApplicationContext ctx = new SpringApplication(IntegrationApplication.class).run(args);
    System.out.println("Hit Enter to terminate");
    System.in.read();
    ctx.close();
  }

}

建立可執行的 JAR

您可以使用 Gradle 或 Maven 從命令列執行應用程式。 您也可以建立一個包含所有必要依賴項、類別和資源的單個可執行 JAR 檔案並執行它。 建立可執行 jar 可以輕鬆地在整個開發生命週期中、跨不同的環境等等,將服務作為應用程式交付、版本化和部署。

如果您使用 Gradle,您可以使用 ./gradlew bootRun 執行應用程式。 或者,您可以使用 ./gradlew build 建立 JAR 檔案,然後執行 JAR 檔案,如下所示

java -jar build/libs/gs-integration-0.1.0.jar

如果您使用 Maven,您可以使用 ./mvnw spring-boot:run 執行應用程式。 或者,您可以使用 ./mvnw clean package 建立 JAR 檔案,然後執行 JAR 檔案,如下所示

java -jar target/gs-integration-0.1.0.jar
此處描述的步驟會建立一個可執行的 JAR。 您也可以 建立一個傳統的 WAR 檔案

執行應用程式

現在您可以執行以下命令,從 jar 執行應用程式

java -jar build/libs/{project_id}-0.1.0.jar

... app starts up ...

應用程式啟動後,它會連接到 RSS feed 並開始提取部落格文章。 應用程式會透過您定義的整合流程來處理這些文章,最終將文章資訊附加到 /tmp/si/SpringBlog 的檔案中。

應用程式執行一段時間後,您應該可以檢視 /tmp/si/SpringBlog 的檔案,以查看一些文章中的資料。 在基於 UNIX 的作業系統上,您也可以執行以下命令,tail 檔案以查看結果,因為它們正在被寫入

tail -f /tmp/si/SpringBlog

您應該會看到類似以下範例輸出的內容(但實際新聞會有所不同)

Spring Integration Java DSL 1.0 GA Released @ https://spring.dev.org.tw/blog/2014/11/24/spring-integration-java-dsl-1-0-ga-released
This Week in Spring - November 25th, 2014 @ https://spring.dev.org.tw/blog/2014/11/25/this-week-in-spring-november-25th-2014
Spring Integration Java DSL: Line by line tutorial @ https://spring.dev.org.tw/blog/2014/11/25/spring-integration-java-dsl-line-by-line-tutorial
Spring for Apache Hadoop 2.1.0.M2 Released @ https://spring.dev.org.tw/blog/2014/11/14/spring-for-apache-hadoop-2-1-0-m2-released

測試

檢查 complete 專案,您將在 src/test/java/com/example/integration/FlowTests.java 中看到一個測試案例

package com.example.integration;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;

import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.integration.endpoint.SourcePollingChannelAdapter;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.messaging.MessageChannel;

import com.rometools.rome.feed.synd.SyndEntryImpl;

@SpringBootTest({ "auto.startup=false",   // we don't want to start the real feed
          "feed.file.name=Test" })   // use a different file
public class FlowTests {

  @Autowired
  private SourcePollingChannelAdapter newsAdapter;

  @Autowired
  private MessageChannel news;

  @Test
  public void test() throws Exception {
    assertThat(this.newsAdapter.isRunning()).isFalse();
    SyndEntryImpl syndEntry = new SyndEntryImpl();
    syndEntry.setTitle("Test Title");
    syndEntry.setLink("http://characters/frodo");
    File out = new File("/tmp/si/Test");
    out.delete();
    assertThat(out.exists()).isFalse();
    this.news.send(MessageBuilder.withPayload(syndEntry).build());
    assertThat(out.exists()).isTrue();
    BufferedReader br = new BufferedReader(new FileReader(out));
    String line = br.readLine();
    assertThat(line).isEqualTo("Test Title @ http://characters/frodo");
    br.close();
    out.delete();
  }

}

此測試使用 Spring Boot 的測試支援來將名為 auto.startup 的屬性設定為 false。 通常來說,依賴於網路連線進行測試並不是一個好主意,尤其是在 CI 環境中。 相反,我們阻止 feed 适配器启动,并将一个 SyndEntry 注入到 news 频道中,以便由流程的其余部分进行处理。测试还设置了 feed.file.name,以便测试写入不同的文件。然后它

  • 驗證适配器已停止。

  • 建立測試 SyndEntry

  • 刪除測試輸出檔案(如果存在)。

  • 傳送訊息。

  • 驗證檔案是否存在。

  • 讀取檔案並驗證資料是否符合預期。

摘要

恭喜! 您已經開發了一個簡單的應用程式,該應用程式使用 Spring Integration 從 spring.io 提取部落格文章、處理它們並將它們寫入檔案。

另請參閱

以下指南也可能很有幫助

想撰寫新的指南或貢獻現有的指南嗎? 請查看我們的 貢獻準則

所有指南均以 ASLv2 授權發布程式碼,並以 署名、禁止衍生創作創用 CC 授權發布寫作。