领先一步
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 中最受欢迎的集成之一(排名前五),但基于事件和基于存储或数据库的触发器更受欢迎。完整列表可在触发器和绑定文档中找到 - 有一个表格,您可以点击特定的绑定或触发器,它将带您到参考页面,其中包含所有语言(包括 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 Dashboard 中找到 - 当您点击相关资源时,通常会有一个 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 Applications 中重复使用相同的配置。
Spring Cloud Function 旨在通过应用开发者声明类型为 java.util.Function
的 Spring Bean 来支持类似的无服务器用例。在 Azure 上使用 Spring Cloud Function 的优点(与普通的 Java 函数相比)在于,实际的业务逻辑代码(原则上)可以移植到其他平台,并且对于现有的 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 清单中的 Main-Class
条目。只要您的应用程序有一个包含一个且仅有一个函数的 main 类,就无需进行其他操作。在示例应用程序中,我们使用清单来定义 main 类
<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 Application,它是函数组的单个部署 artifact。如果您愿意,也可以使用任意的 @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 和 Azure Functions 的演讲。