AWS Lambda
AWS 轉接器會取得 Spring Cloud Function 應用程式,並將其轉換為可在 AWS Lambda 中執行的形式。
如何開始使用 AWS Lambda 的詳細資訊不在本文檔的範圍內,因此預期使用者已熟悉 AWS 和 AWS Lambda,並希望了解 Spring 提供的額外價值。
開始使用
Spring Cloud Function 框架的目標之一是提供必要的基礎架構元素,以使簡單的函數應用程式能夠在特定環境中以特定方式互動。簡單的函數應用程式(在 Spring 的上下文中)是一個包含 Supplier、Function 或 Consumer 類型 Bean 的應用程式。因此,在 AWS 中,這表示簡單的函數 Bean 應以某種方式在 AWS Lambda 環境中被識別和執行。
讓我們看看範例
@SpringBootApplication
public class FunctionConfiguration {
public static void main(String[] args) {
SpringApplication.run(FunctionConfiguration.class, args);
}
@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
}
它展示了一個完整的 Spring Boot 應用程式,其中定義了一個函數 Bean。有趣的是,從表面上看,這只是一個普通的 Boot 應用程式,但在 AWS 轉接器的上下文中,它也是一個完全有效的 AWS Lambda 應用程式。不需要其他程式碼或組態。您只需要封裝並部署它,讓我們看看如何做到這一點。
為了簡化操作,我們提供了一個範例專案,可以隨時建置和部署,您可以在此處存取它。
您只需執行 ./mvnw clean package
即可產生 JAR 檔案。所有必要的 Maven 外掛程式都已設定完成,以產生適用於 AWS 部署的 JAR 檔案。(您可以在JAR 佈局注意事項中閱讀有關 JAR 佈局的更多詳細資訊)。
然後您必須將 JAR 檔案(透過 AWS 儀表板或 AWS CLI)上傳到 AWS。
當被詢問到處理常式時,您指定 org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
,這是一個通用的請求處理常式。

就這樣。儲存並使用一些範例資料執行函數,對於此函數,預期是一個字串,函數將其轉換為大寫並傳回。
雖然 org.springframework.cloud.function.adapter.aws.FunctionInvoker
是一個通用的 AWS RequestHandler
實作,旨在讓您完全隔離於 AWS Lambda API 的細節之外,但在某些情況下,您可能想要指定要使用的特定 AWS RequestHandler
。下一節將說明您如何實現這一點。
AWS 請求處理常式
雖然 AWS Lambda 允許您實作各種 RequestHandlers
,但使用 Spring Cloud Function 時,您不需要實作任何處理常式,而是使用提供的 org.springframework.cloud.function.adapter.aws.FunctionInvoker
,它是 AWS RequestStreamHandler
的實作。使用者在部署函數時,只需要在 AWS 儀表板上將其指定為「處理常式」即可。它將處理大多數情況,包括 Kinesis、串流等。
如果您的應用程式有多個 @Bean
類型為 Function
等,那麼您可以透過設定 spring.cloud.function.definition
屬性或環境變數來選擇要使用的 Bean。這些函數是從 Spring Cloud FunctionCatalog
中提取的。如果您未指定 spring.cloud.function.definition
,框架將嘗試按照搜尋順序尋找預設值,其中它首先搜尋 Function
,然後是 Consumer
,最後是 Supplier
)。
類型轉換
Spring Cloud Function 將嘗試透明地處理原始輸入串流和函數宣告的類型之間的類型轉換。
例如,如果您的函數簽章如下 Function<Foo, Bar>
,我們將嘗試將傳入的串流事件轉換為 Foo
的實例。
如果類型未知或無法確定(例如 Function<?, ?>
),我們將嘗試將傳入的串流事件轉換為泛型 Map
。
原始輸入
有時您可能想要存取原始輸入。在這種情況下,您只需宣告您的函數簽章接受 InputStream
即可。例如,Function<InputStream, ?>
。在這種情況下,我們不會嘗試任何轉換,而是將原始輸入直接傳遞給函數。
AWS 函數路由
Spring Cloud Function 的核心功能之一是路由 - 能夠擁有一個特殊函數,根據使用者提供的路由指示委派給其他函數。
在 AWS Lambda 環境中,此功能提供了一個額外的好處,因為它允許您將單個函數(路由函數)綁定為 AWS Lambda,從而為 API Gateway 提供單個 HTTP 端點。因此,最終您只需管理一個函數和一個端點,同時受益於應用程式中可能包含的許多函數。
提供的範例中提供了更多詳細資訊,但仍有一些一般事項值得一提。
只要您的應用程式中有超過一個函數,路由功能就會預設啟用,因為 org.springframework.cloud.function.adapter.aws.FunctionInvoker
無法確定要綁定為 AWS Lambda 的函數,因此它預設為 RoutingFunction
。這表示您只需要提供路由指示即可,您可以使用多種機制來完成此操作(請參閱範例以取得更多詳細資訊)。
另請注意,由於 AWS 不允許環境變數名稱中使用點 .
和/或連字號 -
,因此您可以受益於 Boot 支援,只需將點替換為底線,將連字號替換為駝峰式命名。因此,例如 spring.cloud.function.definition
變為 spring_cloud_function_definition
,而 spring.cloud.function.routing-expression
變為 spring_cloud_function_routingExpression
。
自訂執行階段
您還可以受益於 AWS Lambda 的 AWS Lambda 自訂執行階段 功能,而 Spring Cloud Function 提供了所有必要的組件,使其變得容易。
從程式碼的角度來看,應用程式應該與任何其他 Spring Cloud Function 應用程式沒有區別。您唯一需要做的就是在 zip/jar 的根目錄中提供一個 bootstrap
腳本,用於執行 Spring Boot 應用程式。並在 AWS 中建立函數時選擇「自訂執行階段」。以下是一個 'bootstrap' 檔案範例
#!/bin/sh
cd ${LAMBDA_TASK_ROOT:-.}
java -Dspring.main.web-application-type=none -Dspring.jmx.enabled=false \
-noverify -XX:TieredStopAtLevel=1 -Xss256K -XX:MaxMetaspaceSize=128M \
-Djava.security.egd=file:/dev/./urandom \
-cp .:`echo lib/*.jar | tr ' ' :` com.example.LambdaApplication
com.example.LambdaApplication
代表您的應用程式,其中包含函數 Bean。
在 AWS 中將處理常式名稱設定為您的函數名稱。您也可以在此處使用函數組合(例如,uppercase|reverse
)。大致就是這樣。一旦您將 zip/jar 上傳到 AWS,您的函數將在自訂執行階段中執行。我們提供了一個範例專案,您也可以在其中了解如何設定您的 POM 以正確產生 zip 檔案。
函數式 Bean 定義樣式也適用於自訂執行階段,並且比 @Bean
樣式更快。自訂執行階段的啟動速度甚至可以比 Java lambda 的函數式 Bean 實作更快 - 這主要取決於您需要在執行階段載入的類別數量。Spring 在這裡沒有做太多事情,因此您可以透過僅在函數中使用原始類型(例如)並不在自訂 @PostConstruct
初始化器中執行任何工作來縮短冷啟動時間。
使用自訂執行階段的 AWS 函數路由
使用自訂執行階段時,函數路由的工作方式相同。您只需要將 functionRouter
指定為 AWS 處理常式,就像您使用函數名稱作為處理常式一樣。
部署容器映像
自訂執行階段也負責處理容器映像部署。以類似於此處描述的方式部署容器映像時,請務必記住設定環境變數 DEFAULT_HANDLER
,其中包含函數的名稱。
例如,對於下面顯示的函數 Bean,DEFAULT_HANDLER
值將為 readMessageFromSQS
。
@Bean
public Consumer<Message<SQSMessageEvent>> readMessageFromSQS() {
return incomingMessage -> {..}
}
此外,務必記住確保 spring_cloud_function_web_export_enabled
也設定為 false
。預設情況下就是如此。
JAR 佈局注意事項
您在 Lambda 中的執行階段不需要 Spring Cloud Function Web 或 Stream 轉接器,因此您可能需要在建立要傳送給 AWS 的 JAR 之前排除這些轉接器。Lambda 應用程式必須是 shaded 的,但 Spring Boot 獨立應用程式則不需要,因此您可以使用 2 個單獨的 jar 執行相同的應用程式(如範例所示)。範例應用程式建立 2 個 jar 檔案,一個帶有 aws
分類器用於在 Lambda 中部署,另一個 可執行(thin)jar,其中包含執行階段的 spring-cloud-function-web
。Spring Cloud Function 將嘗試從 JAR 檔案資訊清單中為您找到「主類別」,使用 Start-Class
屬性(如果您使用 starter parent,Spring Boot 工具會為您新增此屬性)。如果您的資訊清單中沒有 Start-Class
,您可以在將函數部署到 AWS 時使用環境變數或系統屬性 MAIN_CLASS
。
如果您未使用函數式 Bean 定義,而是依賴 Spring Boot 的自動組態,並且不依賴 spring-boot-starter-parent
,則必須將其他轉換器組態為 maven-shade-plugin 執行的一部分。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.7.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>aws</shadedClassifierName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.handlers</resource>
</transformer>
<transformer implementation="org.springframework.boot.maven.PropertiesMergingResourceTransformer">
<resource>META-INF/spring.factories</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.components</resource>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
建置檔案設定
為了在 AWS Lambda 上執行 Spring Cloud Function 應用程式,您可以利用雲端平台提供商提供的 Maven 或 Gradle 外掛程式。
Maven
為了將轉接器外掛程式用於 Maven,請將外掛程式依賴項新增至您的 pom.xml
檔案
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-adapter-aws</artifactId>
</dependency>
</dependencies>
如JAR 佈局注意事項中所述,您需要一個 shaded jar 才能將其上傳到 AWS Lambda。您可以使用 Maven Shade Plugin 來完成此操作。有關設定的範例,請參閱上方。
您可以使用 Spring Boot Maven Plugin 來產生 thin jar。
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot.experimental</groupId>
<artifactId>spring-boot-thin-layout</artifactId>
<version>${wrapper.version}</version>
</dependency>
</dependencies>
</plugin>
您可以在此處找到使用 Maven 將 Spring Cloud Function 應用程式部署到 AWS Lambda 的完整範例 pom.xml
檔案。
Gradle
為了將轉接器外掛程式用於 Gradle,請將依賴項新增至您的 build.gradle
檔案
dependencies {
compile("org.springframework.cloud:spring-cloud-function-adapter-aws:${version}")
}
如JAR 佈局注意事項中所述,您需要一個 shaded jar 才能將其上傳到 AWS Lambda。您可以使用 Gradle Shadow Plugin 來完成此操作
您可以使用 Spring Boot Gradle Plugin 和 Spring Boot Thin Gradle Plugin 來產生 thin jar。
以下是一個完整的 gradle 檔案
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0-M2'
id 'io.spring.dependency-management' version '1.1.3'
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'maven-publish'
id 'org.springframework.boot.experimental.thin-launcher' version "1.0.31.RELEASE"
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
mavenLocal()
maven { url 'https://repo.spring.io/milestone' }
}
ext {
set('springCloudVersion', "2023.0.0-M1")
}
assemble.dependsOn = [thinJar, shadowJar]
publishing {
publications {
maven(MavenPublication) {
from components.java
versionMapping {
usage('java-api') {
fromResolutionOf('runtimeClasspath')
}
usage('java-runtime') {
fromResolutionResult()
}
}
}
}
}
shadowJar.mustRunAfter thinJar
import com.github.jengelman.gradle.plugins.shadow.transformers.*
shadowJar {
archiveClassifier = 'aws'
manifest {
inheritFrom(project.tasks.thinJar.manifest)
}
// Required for Spring
mergeServiceFiles()
append 'META-INF/spring.handlers'
append 'META-INF/spring.schemas'
append 'META-INF/spring.tooling'
append 'META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports'
append 'META-INF/spring/org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration.imports'
transform(PropertiesFileTransformer) {
paths = ['META-INF/spring.factories']
mergeStrategy = "append"
}
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.cloud:spring-cloud-function-adapter-aws'
implementation 'org.springframework.cloud:spring-cloud-function-context'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
tasks.named('test') {
useJUnitPlatform()
}
您可以在此處找到使用 Gradle 將 Spring Cloud Function 應用程式部署到 AWS Lambda 的完整範例 build.gradle
檔案。