介紹 Spring Cloud Function

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

Spring Cloud Function 是一個新專案,其主要目標如下

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

正如 Spring 一直推廣基於普通舊 Java 物件(POJO)的程式設計模型一樣,Spring Cloud Function 推廣基於普通舊函式的程式設計模型。這意味著 java.util.function 包中定義的核心介面:FunctionConsumerSupplier

這些型別的實現可以透過顯式或隱式方式註冊為 bean,透過 @FunctionScan 啟用的類路徑掃描。引數和/或返回型別可以選擇使用 Reactor 的 Flux,它是一個 Reactive Streams Publisher。這使得與其他的 Reactive Streams 元件(即使是基於其他實現的,如 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;
  }
}

但是如果您需要實現將資料集作為處理單元的函式,透過視窗化或歸約操作,您可以使用 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 現在常用一樣。

您可能會問,既然您可以輕鬆建立 FunctionConsumerSupplier 例項,為什麼 Spring 推廣這種模型是必要的。答案涉及控制反轉(Inversion of Control),這應該不足為奇。多年來,從基本的依賴注入到 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 本身提供了所有這些功能。這是將控制反轉提升到另一個層次的又一個案例。

在本部落格系列的第二部分,我們將提供關於如何在下一版 Spring Cloud Data Flow 中使用 SuppliersFunctionsConsumers 的示例。基本思想是,無論何時您需要提供一些自定義邏輯,您都可以簡單地實現函式。這是一個有主見的模型的完美示例,您不僅不需要提供樣板程式碼,而且最好還是讓框架來處理這些。例如,您將能夠只註冊函式——可以是內聯的,也可以打包成 JAR(而不是 Spring Cloud Stream 應用),然後在 DSL 中引用它們,同時依靠 Spring Cloud Data Flow 為您包裝它們

mySupplier | myFunction | myConsumer

部署配置檔案甚至擴充套件到了無伺服器(又稱函式即服務,FaaS)提供商領域,例如 AWS Lambda 和 Apache OpenWhisk(以及一旦支援 Java 的 Azure Functions 和 Google Cloud Functions)。在本部落格系列的第三部分,我們將深入探討該主題的更多細節,但現在您可以查閱 AWS Lambda 介面卡Apache OpenWhisk 介面卡 的文件。即將釋出的部落格也將涵蓋與基於 Kubernetes 的無伺服器框架(如 Fission)的整合。

除了將業務邏輯與基礎設施解耦的作用之外,各種部署配置檔案 JAR 和 FaaS 介面卡還提高了可移植性。開發人員可以完全獨立地實現一個函式,包括只關注輸入和輸出引數的單元測試。然後可以將該函式與允許其在目標環境中執行的依賴項一起打包,目標環境範圍從獨立的 REST 應用到 Spring Cloud Data Flow 或 FaaS 提供商。

這帶我們來到了這篇介紹性部落格的最後一點。“無伺服器”(Serverless)一詞引起了很多反對,並且幾乎總是伴隨著解釋:“當然仍然有伺服器,但您無需考慮它們。” 因此,雖然我們將避免引入“無框架”(Frameworkless)一詞,但相同的概念確實可以應用於框架。在上面的 Spring Cloud Data Flow 示例中,函式開發人員無需考慮框架,甚至不需要生成其依賴項中包含任何框架程式碼的 artifact。同樣的想法也適用於 FaaS 介面卡。我們基本上是將控制反轉推向極致,可以將好萊塢原則扭轉為:“不要依賴我們,我們將依賴您”。這在好萊塢可能行不通,但對於開發人員來說,這意味著您只需編寫一個函式,將其打包到 JAR 中,然後註冊它以便與各種端點或介面卡一起使用。Spring 一如既往地遵循 Alan Kay 巧妙闡述的原則:“簡單的事情應該簡單。複雜的事情應該成為可能。” 在即將釋出的部落格文章中,我們將深入探討由於 Spring Cloud Function 而可能實現的一些更復雜的事情,但我們永遠不會忘記保持簡單的事情簡單。

敬請關注!

訂閱 Spring 郵件列表

訂閱 Spring 郵件列表,保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速發展。

瞭解更多

獲取支援

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

瞭解更多

即將舉辦的活動

檢視 Spring 社群的所有即將舉辦的活動。

檢視全部