133. 无服务器平台适配器

除了能够作为独立进程运行之外,Spring Cloud Function 应用程序还可以适应运行现有的无服务器平台之一。在项目中,有AWS LambdaAzureApache OpenWhisk的适配器。 Oracle Fn 平台拥有自己的 Spring Cloud Function 适配器。 Riff支持 Java 函数,其Java 函数调用器本身是 Spring Cloud Function jar 的适配器。

133.1 AWS Lambda

AWS适配器需要一个 Spring Cloud Function 应用程序,并将其转换为可以在 AWS Lambda 中运行的表单。

133.1.1 Introduction

适配器具有几个可以使用的通用请求处理程序。最通用的是SpringBootStreamHandler,它使用 Spring Boot 提供的 Jackson ObjectMapper来序列化和反序列化函数中的对象。您还可以扩展一个SpringBootRequestHandler,并将 Importing 和输出类型作为类型参数提供(使 AWS 能够检查类并自己进行 JSON 转换)。

如果您的应用具有多个Function等类型的@Bean,则可以通过配置function.name(例如在 AWS 中将FUNCTION_NAME作为环境变量)来选择要使用的@Bean。从 Spring Cloud FunctionCatalog中提取函数(首先搜索Function,然后搜索Consumer,最后搜索Supplier)。

133.1.2 有关 JAR 布局的注意事项

Lambda 在运行时不需要 Spring Cloud Function Web 或 Stream 适配器,因此在创建发送到 AWS 的 JAR 之前,可能需要排除那些适配器。 Lambda 应用程序必须着色,但 Spring Boot 独立应用程序不必着色,因此您可以使用 2 个单独的 jar(根据示例)运行同一应用程序。该示例应用程序将创建 2 个 jar 文件,其中一个带有aws分类器以在 Lambda 中进行部署,另一个是可执行(瘦)jar,其中包含spring-cloud-function-web在运行时。 Spring Cloud Function 将尝试使用Start-Class属性(如果使用Starter Parent,则将由 Spring Boot 工具为您添加)从 JAR 文件清单中为您找到“主类”。如果清单中没有Start-Class,则在将功能部署到 AWS 时可以使用环境变量MAIN_CLASS

133.1.3 Upload

spring-cloud-function-samples/function-sample-aws下构建示例,并将-aws jar 文件上传到 Lambda。处理程序可以是example.Handlerorg.springframework.cloud.function.adapter.aws.SpringBootStreamHandler(该类的 FQN,不是方法参考,尽管 Lambda 确实接受方法参考)。

./mvnw -U clean package

使用 AWS 命令行工具,如下所示:

aws lambda create-function --function-name Uppercase --role arn:aws:iam::[USERID]:role/service-role/[ROLE] --zip-file fileb://function-sample-aws/target/function-sample-aws-2.0.0.BUILD-SNAPSHOT-aws.jar --handler org.springframework.cloud.function.adapter.aws.SpringBootStreamHandler --description "Spring Cloud Function Adapter Example" --runtime java8 --region us-east-1 --timeout 30 --memory-size 1024 --publish

AWS 示例中函数的 Importing 类型是 Foo,它具有一个称为“ value”的单个属性。因此,您需要使用它进行测试:

{
  "value": "test"
}

Note

AWS 示例应用程序以“功能性”风格(作为ApplicationContextInitializer)编写。与传统的@Bean样式相比,这在 Lambda 中的启动速度要快得多,因此,如果不需要@Beans(或@EnableAutoConfiguration),这是一个不错的选择。暖启动不受影响。

133.1.4 Platfom 的特定功能

HTTP 和 API 网关

AWS 具有某些特定于平台的数据类型,包括消息批处理,这比单独处理每个数据集要高效得多。要使用这些类型,您可以编写依赖于这些类型的函数。或者,您可以依靠 Spring 从 AWS 类型中提取数据并将其转换为 Spring Message。为此,您告诉 AWS 该函数具有特定的通用处理程序类型(取决于 AWS 服务),并提供Function<Message<S>,Message<T>>类型的 Bean,其中ST是您的业务数据类型。如果有多个类型为Function的 bean,您可能还需要将 Spring Boot 属性function.name配置为目标 bean 的名称(例如,使用FUNCTION_NAME作为环境变量)。

支持的 AWS 服务和通用处理程序类型如下:

ServiceAWS TypesGeneric Handler
API GatewayAPIGatewayProxyRequestEvent , APIGatewayProxyResponseEventorg.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler
KinesisKinesisEventorg.springframework.cloud.function.adapter.aws.SpringBootKinesisEventHandler

例如,要在 API 网关后面部署,请在 AWS 命令行中使用--handler org.springframework.cloud.function.adapter.aws.SpringBootApiGatewayRequestHandler(通过 UI 进行 Importing),并定义Function<Message<Foo>,Message<Bar>>类型的@Bean,其中FooBar是 POJO 类型(AWS 使用 Jackson 将对数据进行编组和解组) 。

133.2 Azure 函数

Azure适配器引导 Spring Cloud Function 上下文,并在必要时使用 Spring Boot 配置将来自 Azure 框架的函数调用引导到用户函数中。 Azure Functions 具有一个非常独特但具有侵入性的编程模型,其中涉及特定于平台的用户代码中的 Comments。在 Spring Cloud 中使用它的最简单方法是扩展 Base Class,并使用@FunctionName注解在其中编写方法,该注解委派给 Base Class 方法。

该项目为 Azure 上的 Spring Cloud Function 应用程序提供了一个适配器层。您可以编写一个类型为Function的单个@Bean的应用程序,如果正确放置了 JAR 文件,则可以在 Azure 中部署该应用程序。

必须扩展一个AzureSpringBootRequestHandler,并提供 Importing 和输出类型作为带 Comments 的方法参数(使 Azure 能够检查类并创建 JSON 绑定)。Base Class 有两个有用的方法(handleRequesthandleOutput),您可以将实际的函数调用委派给该方法,因此大多数情况下,该函数只会有一行。

Example:

public class FooHandler extends AzureSpringBootRequestHandler<Foo, Bar> {
	@FunctionName("uppercase")
	public Bar execute(
			@HttpTrigger(name = "req", methods = { HttpMethod.GET,
					HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS)
                    Foo foo,
			ExecutionContext context) {
		return handleRequest(foo, context);
	}
}

此 Azure 处理程序将委派给Function<Foo,Bar> bean(或Function<Publisher<Foo>,Publisher<Bar>>)。某些 Azure 触发器(例如@CosmosDBTrigger)导致 Importing 类型为List,在这种情况下,您可以绑定到 Azure 处理程序中的ListString(原始 JSON)。 ListImporting 委托给 Importing 类型为Map<String,Object>或相同类型PublisherListFunctionFunction的输出可以是List(一对一)或单个值(聚合),并且 Azure 声明中的输出绑定应该匹配。

如果您的应用具有多个@Bean类型Function等,那么您可以通过配置function.name选择要使用的一个。或者,如果使 Azure 处理程序方法中的@FunctionName与函数名称匹配,则它应以这种方式工作(也适用于具有多个功能的函数应用程序)。这些函数是从 Spring Cloud FunctionCatalog中提取的,因此默认函数名称与 Bean 名称相同。

133.2.1 有关 JAR 布局的注意事项

在 Azure 的运行时中不需要 Spring Cloud Function Web,因此可以在创建部署到 Azure 的 JAR 之前将其排除在外,但是如果包含它,则不会使用它,因此保留它不会有任何伤害上。Azure 上的功能应用程序是由 Maven 插件生成的存档。该函数位于此项目生成的 JAR 文件中。该示例使用精简版式将其创建为可执行 jar,以便 Azure 可以找到处理程序类。如果愿意,可以只使用常规的平面 JAR 文件。依赖性不应该包括在内。

133.2.2 Build

./mvnw -U clean package

133.2.3 运行示例

您可以像其他 Spring Cloud Function 示例一样在本地运行示例:

curl -H "Content-Type: text/plain" localhost:8080/function -d '{"value": "hello foobar"}'

您将需要az CLI 应用程序(有关更多详细信息,请参见https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven)。要将功能部署在 Azure 运行时上:

$ az login
$ mvn azure-functions:deploy

在另一个终端上,尝试以下操作:curl https://<azure-function-url-from-the-log>/api/uppercase -d '{"value": "hello foobar!"}'。请确保为以上功能使用正确的 URL。或者,您可以在 Azure 仪表板 UI 中测试该功能(单击功能名称,转到右侧,然后单击“测试”,然后单击右下角的“运行”)。

Azure 示例中函数的 Importing 类型是具有单个属性“ Foo”的 Foo。因此,您需要使用以下代码进行测试:

{
  "value": "foobar"
}

Note

Azure 示例应用程序以“非功能性”样式编写(使用@Bean)。在 Azure 中,功能样式(仅具有FunctionApplicationContextInitializer)在启动时要比传统的@Bean样式快得多,因此,如果不需要@Beans(或@EnableAutoConfiguration),则是一个不错的选择。暖启动不受影响。

133.3 Apache Openwhisk

OpenWhisk适配器采用可执行 jar 的形式,可在 docker 映像中使用,以部署到 Openwhisk。该平台以请求-响应模式工作,侦听特定端点上的端口 8080,因此该适配器是一个简单的 Spring MVC 应用程序。

133.3.1 快速Starter

实施 POF(确保使用functions软件包):

package functions;

import java.util.function.Function;

public class Uppercase implements Function<String, String> {

	public String apply(String input) {
		return input.toUpperCase();
	}
}

将其安装到本地 Maven 存储库中:

./mvnw clean install

创建一个提供其 Maven 坐标的function.properties文件。例如:

dependencies.function: com.example:pof:0.0.1-SNAPSHOT

将 openwhisk 运行程序 JAR 复制到工作目录(与属性文件相同的目录):

cp spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/target/spring-cloud-function-adapter-openwhisk-2.0.0.BUILD-SNAPSHOT.jar runner.jar

使用上述属性文件从运行器 JAR 的--thin.dryrun生成一个 m2repo:

java -jar -Dthin.root=m2 runner.jar --thin.name=function --thin.dryrun

使用以下 Dockerfile:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY m2 /m2
ADD runner.jar .
ADD function.properties .
ENV JAVA_OPTS=""
ENTRYPOINT [ "java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "runner.jar", "--thin.root=/m2", "--thin.name=function", "--function.name=uppercase"]
EXPOSE 8080

Note

Note

您可以使用 Spring Cloud Function 应用程序,而不仅仅是使用其中装有 POF 的 jar,在这种情况下,您将不得不更改应用程序在容器中的运行方式,以便它将主类用作源文件。例如,您可以更改上面的ENTRYPOINT并添加--spring.main.sources=com.example.SampleApplication

构建 Docker 映像:

docker build -t [username/appname] .

推送 Docker 映像:

docker push [username/appname]

使用 OpenWhisk CLI(例如vagrant ssh之后)创建操作:

wsk action create example --docker [username/appname]

调用动作:

wsk action invoke example --result --param payload foo
{
    "result": "FOO"
}