Spring Cloud Function 簡介

工程 | Mark Fisher | 2017 年 7 月 5 日 | ...

Spring Cloud Function 是一個新專案,具有以下高階目標

  • 推廣透過函數實作業務邏輯。
  • 將業務邏輯的開發生命週期與任何特定執行階段目標解耦,以便相同的程式碼可以作為網路端點、串流處理器或任務執行。
  • 支援跨無伺服器供應商的統一程式設計模型,以及獨立執行(在本機或在 PaaS 中)的能力。
  • 在無伺服器供應商上啟用 Spring Boot 功能(自動配置、依賴注入、指標)。

正如 Spring 一直以來推廣基於純舊 Java 物件 (POJO) 的程式設計模型一樣,Spring Cloud Function 推廣基於純舊函數的程式設計模型。我們指的是在 java.util.function 套件中定義的核心介面:FunctionConsumerSupplier

這些類型的實作可以明確地或隱含地透過類別路徑掃描(由 @FunctionScan 啟用)註冊為 bean。參數和/或回傳類型可以選擇性地使用 Reactor 的 Flux,這是一個反應式串流 Publisher。這能夠與其他反應式串流元件互通操作,即使是那些基於其他實作的元件,例如 RxJava 2,並且它為此處理模型帶來了反應式功能,例如非阻塞 IO 和背壓(如需更多資訊,請參閱 Project Reactor)。每當參數和/或回傳類型不是 Flux 時,Spring Cloud Function 都會包裝它們,以便函數可以透過 Flux 互通操作。對於簡單的逐項處理用例,您可以保持簡單

public class Greeter implements Function<String, String> {
  public String apply(String name) {
    return "Hello " + name;
  }
}

但是,如果您需要實作將資料集作為處理單位的函數,透過視窗化或 reduce 運算,您可以使用 Flux 類型

public static class WordCount
    implements Function<Flux<String>, Flux<Map<String, Integer>>> {
  public Flux<Map<String, Integer>> apply(Flux<String> phrases) {
    return phrases.window(3)
      .flatMap(f -> f.flatMap(phrase -> Flux.fromArray(phrase.split("\\W")))
      .reduce(new HashMap<String, Integer>(),
        (map, word) -> { map.merge(word, 1, Integer::sum); return map; }));
  }
}

依賴函數類型也使得組合功能變得容易,例如

twistAndShout = twist.andThen(shout);

當然,函數也可以使用 Lambda 表達式定義,例如

Function<String, String> shout =  s -> s.toUpperCase() + “!”;

事實上,Spring Cloud Function 支援將基於字串的 Lambda 表達式動態編譯為函數實例。當原型設計或新增一些簡單的轉換邏輯時,這可能特別有用,就像今天常用的 Spring Expression Language 一樣。

您可能會問,為什麼 Spring 有必要推廣此模型,因為您可以輕鬆地建立 FunctionConsumerSupplier 實例。得知答案涉及控制反轉,應該不會太令人驚訝。多年來,從基本的依賴注入到 Spring 普遍使用的範本模式,所有的一切都以好萊塢原則來描述:「不要打電話給我們,我們會打電話給你」。上面提到的 Flux 適配實際上是控制反轉的一個例子,但更重要的是業務邏輯與部署配置文件的解耦。在這種情況下,業務邏輯指的是函數,而部署配置文件可以是 REST 應用程式、串流處理應用程式或有限任務。Spring Cloud Function 為每種類型提供一個 JAR,並且在每種情況下,都會使用自動配置的 FunctionCatalog 來定位 ApplicationContext 中的 FunctionsConsumersSuppliers

例如,要將上面顯示的 Greeter 函數部署為 REST 端點,只需新增 "spring-cloud-function-web" 依賴項,如此 POM 中所示。這也包括 Spring Boot Maven 外掛程式,以便建置產生可執行 JAR

./mvnw clean install
java -jar greeter/target/greeter-0.0.1-SNAPSHOT.jar

然後可以使用 curl 呼叫它

$ curl -H "Content-Type: text/plain" :8080/greeter -d World
Hello World

同樣地,要將函數部署為串流處理器,只需新增 "spring-cloud-function-stream" 依賴項,該依賴項又建立在 Spring Cloud Stream 之上。正如 Spring Cloud Stream 提供了一個 Binder 抽象,消除了定義 Channel Adapters 的需要,Spring Cloud Function 消除了宣告元件(例如 Service Activators、Transformers,甚至 Spring Cloud Stream 委派給的 @StreamListener 註解方法)的需要。"spring-cloud-function-stream" JAR 本身提供了所有這些。這是將控制反轉提升到另一個層次的又一個案例。

在本部落格系列的第 2 部分中,我們將提供範例說明如何在下一版本的 Spring Cloud Data Flow 中使用 SuppliersFunctionsConsumers。基本概念是,每當您需要提供一些自訂邏輯時,您可以只實作簡單的函數。這是意見主導模型的完美範例,您不僅不需要提供樣板程式碼,而且框架最好還是處理它。例如,您將能夠僅註冊函數 - 以內聯或封裝為 JAR 的形式(而不是 Spring Cloud Stream 應用程式),然後在 DSL 中引用這些函數,同時依賴 Spring Cloud Data Flow 為您包裝它們

mySupplier | myFunction | myConsumer

部署配置文件甚至擴展到無伺服器(又名函數即服務)供應商的領域,例如 AWS Lambda 和 Apache OpenWhisk(以及 Azure Functions 和 Google Cloud Functions,一旦它們提供 Java 支援)。在本部落格系列的第 3 部分中,我們將更深入地探討該主題,但現在您可以仔細閱讀 AWS Lambda 適配器Apache OpenWhisk 適配器的文件。即將發表的部落格也將涵蓋與基於 Kubernetes 的無伺服器框架(例如 Fission)的整合。

除了將業務邏輯和基礎架構解耦的角色之外,各種部署配置文件 JAR 和 FaaS 適配器還提高了可移植性。開發人員可以完全隔離地實作函數,包括僅關注輸入和輸出參數的單元測試。然後,可以將該函數與允許它在目標環境中運行的依賴項一起封裝,範圍從獨立 REST 應用程式到 Spring Cloud Data Flow 或 FaaS 供應商。

這將我們帶到了本入門部落格的最後一點。「無伺服器」一詞引起了很多反彈,並且幾乎總是接著解釋:「當然仍然有伺服器,但您不必考慮它們。」因此,雖然我們會抵制引入「無框架」一詞,但相同的概念確實可以應用於框架。在上面的 Spring Cloud Data Flow 範例中,函數開發人員不需要考慮框架,甚至不需要產生在其依賴項中具有任何框架程式碼的工件。相同的想法也適用於 FaaS 適配器。我們基本上是將控制反轉推向極致,以至於我們可以將好萊塢原則扭曲為:「不要依賴我們,我們會依賴您」。這在好萊塢可能不受歡迎,但對於開發人員來說,這意味著您可以只編寫一個函數,將其封裝在 JAR 中,並註冊以用於各種端點或適配器。與往常一樣,Spring 遵循 Alan Kay 雄辯地陳述的原則:「簡單的事情應該簡單。複雜的事情應該是可能的。」在即將發表的部落格文章中,我們將深入探討由於 Spring Cloud Function 而成為可能的一些更複雜的事情,但我們永遠不會忘記保持簡單的事情簡單。

敬請關注!

取得 Spring 電子報

隨時掌握 Spring 電子報的最新資訊

訂閱

領先一步

VMware 提供訓練和認證,以加速您的進展。

了解更多

取得支援

Tanzu Spring 在一個簡單的訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將到來的活動

查看 Spring 社群中所有即將到來的活動。

查看全部