领先一步
VMware提供培训和认证,助您快速提升技能。
了解更多Spring Cloud Function 自1.0版本以来一直支持Microsoft Azure Functions,但在最新的2.0版本(仍处于里程碑阶段)中,我们决定稍微更改编程模型。本文介绍了这些更改对用户的意义,并简要介绍了这一转变背后的原因。Spring团队在开发过程中与Microsoft团队进行了很多愉快的合作,为我们的用户提供了这两项技术的最佳结合。
Microsoft 一直以来都为 Azure Functions 提供 Java 支持,这使开发人员能够轻松编写和部署 Java 代码,从而以无服务器方式连接到 Azure 中的各种平台服务(事件、数据库、存储、HTTP 网关等)。它采用基于注解的编程模型,将函数实现置于 Java 方法中。因此,您可以编写一个方法并使用 `@FunctionName` 注解它,它就变成了一个 Azure 函数。它提供了一套丰富的基于 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 事件中心作为输入和 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 仪表板中找到——当您点击相关资源时,通常会看到一个“连接字符串”(或类似的)链接,您可以将其复制粘贴到本地进程(例如,在本地运行但未签入源代码管理的脚本中)。例如,您可以使用这样的 `setup-env.sh` 脚本
export PRODUCT_ITEMS_DOCUMENTDB_CONNECTION_STRING="AccountEndpoint=https://..."
export TRANSACTIONS_EVENT_HUB_CONNECTION_STRING="Endpoint=sb://..."
并在终端会话开始时对其进行引用。
示例中 `pom.xml` 中还有一些其他的插件声明。它们都很重要,但基本上是样板代码——您应该能够复制它们并在所有 Azure 函数应用程序中重复使用相同的配置。
当应用程序开发人员声明 `java.util.Function` 类型的 Spring bean 时,Spring Cloud Function 旨在支持类似的无服务器用例。在 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` 是通用的,具有输入和输出类型参数。您必须将输入类型与传入的事件数据匹配,Azure 将使用 Jackson 在 Spring 进行任何操作之前将其以 JSON 格式呈现并转换。基类中有两个实用程序方法,一个(`handle`)返回响应对象,另一个(`handleOutput`)接受 `OutputBinding` 并将其绑定到用户 `Function` 的输出。
注意
基类纯粹是样板代码,仅作为将您的 Spring 函数绑定到无服务器平台服务的外部表示。如果您在其他平台或本地通过 Spring Cloud Function Web 适配器运行,则 Azure 绑定将被忽略。将来可能可以用接口声明替换它——Azure 平台目前不允许这样做,但这是我们正在与 Microsoft 团队一起研究的内容。
有各种配置选项可以驱动 Azure 函数的运行时行为。最重要(也是唯一强制性)的一个是 `MAIN_CLASS`,它是包含 `Function`(或 `Functions`)声明的主要 `@SpringBootApplication` 类。您可以将其指定为环境变量,也可以将其指定为应用程序 jar 清单中的 `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 函数应用程序,这是一个函数组的单个部署工件。如果您愿意,也可以使用任意 `@FunctionName` 并通过环境变量 `FUNCTION_NAME` 或 `application.properties` 中的 `function.name` 配置 Spring Cloud 函数名称。
在项目存储库中还有另一个关于如何将 Spring Cloud Function 设置为 Azure 函数的简单示例——这是一个从 Azure 角度来看的 HTTP 触发器,但 Spring Cloud Function 部分非常相似。
注意
如果您本周参加了Spring One Platform,欢迎参加Jeff Hollan(微软)和Oleg Zhurakousky(Pivotal)关于Spring和Azure Functions的演讲。