领先一步
VMware 提供培训和认证,助您加速进步。
了解更多Spring Cloud Function 自 1.0 版本起就支持 Microsoft Azure Functions,但在最新的 2.0 版本(仍处于里程碑阶段)中,我们决定对编程模型进行一些更改。本文将介绍这些更改对用户意味着什么,并提供一些关于此次调整的背景信息。Spring 团队非常乐意与 Microsoft 的同事们合作,为用户带来这两项技术的最佳结合。
Microsoft 的 Azure Functions 早已支持 Java,它使开发人员能够轻松编写和部署 Java 代码,以无服务器的方式连接到 Azure 中的各种平台服务(事件、数据库、存储、HTTP 网关等)。它提供了一个基于注解的编程模型,将函数实现放在 Java 方法中。因此,您只需编写一个方法并使用 @FunctionName 进行注解,它就会成为一个 Azure Function。目前有一套丰富的工具,基于 Maven 插件,可以驱动 Azure 命令行,用于构建函数、本地运行和调试,以及将其部署到云端。Azure 网站上有一个 快速入门指南,可以帮助您安装和配置所有先决条件,并且在 开发人员指南 中有关于 Azure Functions 工作原理的更详细文档。
这些注解还将函数方法的参数和返回类型与部署时使用的服务绑定。例如,如果您想在部署时绑定到 HTTP 网关,可以使用 @HttpTrigger。
@FunctionName("uppercase")
public Bar execute(
@HttpTrigger(name = "req", methods = { HttpMethod.GET, HttpMethod.POST },
authLevel = AuthorizationLevel.ANONYMOUS) Foo foo,
ExecutionContext context) {
return new Bar(foo.getValue());
}
在此示例中,我们接受一个传入的 HTTP POST 请求,Azure 将其正文绑定到一个类型为 Foo 的 POJO。我们将 Foo 转换为 Bar,然后通过 HTTP 响应返回给调用者。
HTTP 触发器是 Azure Functions 中最受欢迎的 5 种集成之一,但基于事件、存储或数据库的触发器更受欢迎。完整的列表可以在 触发器和绑定 文档中找到——其中有一个表格,您可以点击特定的绑定或触发器,它将带您到参考页面,其中包含所有语言的代码示例,包括 Java。
以下是另一个示例,使用 Azure Event Hub 作为输入,Cosmos DB 作为输出。此示例 在 GitHub 上。
@FunctionName("uppercase")
public Bar execute(
@EventHubTrigger(name = "data", eventHubName = "events",
connection = "TRANSACTIONS_EVENT_HUB_CONNECTION_STRING")
Foo data,
@CosmosDBOutput(name = "document", databaseName = "inventory",
collectionName = "messages",
connectionStringSetting = "PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING",
createIfNotExists = true)
OutputBinding<Bar> document,
final ExecutionContext context) {
return document.setValue(new Bar(foo.getValue()));
}
注意
如果传入的 JSON 无法转换为函数输入类型(在此例中为 Foo),您将看到 Azure 出现一个令人困惑的 no such method 错误。如果您遇到这种情况,可以尝试将 @FunctionName 方法的输入更改为 String,然后手动检查数据以确保它可以绑定到所需的输入类型。
这些注解通过间接引用传递连接凭据信息给在函数部署中配置的环境变量。所有这些配置都在 pom.xml 文件中通过 Azure Functions Maven 插件进行。例如:
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-functions-maven-plugin</artifactId>
<configuration>
<resourceGroup>${functionResourceGroup}</resourceGroup>
<appName>${functionAppName}</appName>
<region>${functionAppRegion}</region>
<appSettings>
<property>
<name>FUNCTIONS_EXTENSION_VERSION</name>
<value>beta</value>
</property>
<property>
<name>TRANSACTIONS_EVENT_HUB_CONNECTION_STRING</name>
<value>${TRANSACTIONS_EVENT_HUB_CONNECTION_STRING}</value>
</property>
<property>
<name>PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING</name>
<value>${PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING}</value>
</property>
<property>
<name>MSDEPLOY_RENAME_LOCKED_FILES</name>
<value>1</value>
</property>
</appSettings>
</configuration>
<executions>
<execution>
<id>package-functions</id>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
在这种情况下,环境变量名将插件配置与函数绑定声明关联起来。例如,@EventHubTrigger 的 connection 属性将在运行时从 TRANSACTIONS_EVENT_HUB_CONNECTION_STRING 环境变量中填充。该插件使用同名的本地环境变量(注意 ${} 占位符)远程配置它,开发者或 CI 进程负责在运行时进行设置。
您自己的个人连接字符串是敏感信息,可以在 Azure 仪表板 中找到——当您点击相关资源时,通常会有一个 Connection Strings 链接(或类似名称),您可以将其复制并粘贴到本地进程中(例如,在一个您在本地运行但不提交到源代码控制的脚本中)。例如,您可以使用像这样的 setup-env.sh 脚本:
export PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING="AccountEndpoint=https://..."
export TRANSACTIONS_EVENT_HUB_CONNECTION_STRING="Endpoint=sb://..."
并在终端会话开始时 source 它一次。
在示例的 pom.xml 中还有一些其他的插件声明。它们都很重要,但基本上是样板代码——您可以将它们复制并在所有 Azure Function 应用程序中重用相同的配置。
Spring Cloud Function 旨在支持类似的无服务器用例,其中应用程序开发人员声明 java.util.Function 类型的 Spring bean。与原生 Java 函数相比,在 Azure 上使用 Spring Cloud Function 的优势在于,实际业务逻辑代码(原则上)可以移植到其他平台,并且对于现有的 Spring 用户来说,这是一个熟悉的编程模型。此外,Spring 的所有常规优势也适用:依赖注入以及与许多其他 Java 库的全面集成。
上面两个示例的等价物将是单个 @Bean。
@Bean
public Function<Foo, Bar> uppercase() {
return foo -> new Bar(foo.getValue().toUpperCase());
}
在 Spring Cloud Function 1.0 版本中,用户必须手动将 Microsoft 注解映射到 JSON 部署描述符,并手动将其打包到具有适合该平台的布局的归档文件中。这个过程很脆弱(但独立于 Azure Java 编程模型)。
在 2.0 版本中,这仍然会奏效,但我们选择更明确地支持 Azure 注解的使用。因此,我们现在有一个基类,应用程序开发人员可以继承它并用 Azure 注解进行装饰。上面的示例将是完全相同的 @Bean,并将上面一个 execute 方法插入到 Spring Cloud 处理程序的子类中。示例:
public class UppercaseHandler extends AzureSpringBootRequestHandler<Foo, Bar> {
@FunctionName("uppercase")
@HttpTrigger(name = "req", methods = { HttpMethod.GET,
HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) Foo foo,
ExecutionContext context) {
return super.handle(foo, context);
}
请注意,基类 AzureSpringBootRequestHandler 是泛型的,带有输入和输出的类型参数。您必须将输入类型与传入的事件数据匹配,这些数据将以 JSON 格式呈现,并在 Spring 处理之前由 Azure 使用 Jackson 进行转换。基类中有两个实用方法:一个(handle)返回响应对象,另一个(handleOutput)接受一个 OutputBinding 并将其绑定到用户 Function 的输出。
注意
该基类是纯粹的样板代码,仅作为将您的 Spring 函数与无服务器平台服务绑定的外部表示。如果您在不同的平台运行,或者通过 Spring Cloud Function Web 适配器在本地运行,Azure 绑定将被忽略。未来有可能用接口声明替换它——Azure 平台目前不允许这样做,但这是我们正在与 Microsoft 团队研究的内容。
有各种配置选项可以驱动 Azure Function 的运行时行为。最重要(也是唯一强制性)的是 MAIN_CLASS,它是包含 Function(或 Functions)声明的主 @SpringBootApplication 类。您可以将其指定为环境变量,或作为应用程序 jar manifest 中的 Main-Class 条目。只要您的应用程序有一个只有一个函数的 main class,就不需要做其他事情。在示例应用程序中,我们使用 manifest 来定义 main class:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>example.FunctionApplication</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
如果您的应用程序有多个 Function bean,它们可以通过 @FunctionName 注解映射到 Azure 函数——bean 名称(或更准确地说,是 FunctionCatalog 中的名称)与函数名称匹配。通过这种方式,您可以创建一个 Azure Function 应用程序,这是一个用于一组函数的单个部署工件。如果您愿意,也可以使用任意的 @FunctionName,并通过环境变量 FUNCTION_NAME 或 application.properties 中的 function.name 来配置 Spring Cloud Function 名称。
在 项目仓库 中有一个关于如何将 Spring Cloud Function 设置为 Azure Function 的简单示例——从 Azure 的角度来看,这个示例是一个 HTTP 触发器,但 Spring Cloud Function 部分非常相似。
注意
如果您在本周参加 Spring One Platform,请参加 Jeff Hollan(Microsoft)和 Oleg Zhurakousky(Pivotal)关于“使用 Spring 和 Microsoft Azure 运行无服务器应用程序”的 演示文稿。