领先一步
VMware 提供培训和认证,助你快速提升。
了解更多Spring Cloud Function 在 2.0 版本(仍处于里程碑阶段)中有一些新特性,其中最显著的可能是实现“完全函数式”的能力。这得益于 Spring Boot 2.1 和 Spring Framework 5.1 的变化,它意味着 Spring 应用中 Bean 定义的一种不同思考方式,同时也显著提升了启动性能。
最好用一张图来开头,特别是它能讲述一个故事时。这里有一张图,展示了 Spring Cloud Function 2.0 相较于 1.0 的改进,比较了 AWS 冷启动的成本。
x 轴是内存大小(MB),y 轴是冷启动成本(GBsec)。最显著的效果体现在低内存容器上,2.0 版本的成本几乎是 1.0 版本的四分之一。“Custom”函数更快(比 Spring Cloud Function 1.0 快 10 倍)——它是一个使用 Spring Cloud Function 和函数式 Bean 的自定义 AWS 运行时。改进的根本原因在于启动时间的显著缩短,这又来源于在应用程序中使用了函数式的 Bean 定义形式。如果你需要入门介绍,Josh 很久以前做了一个关于函数式 Bean 注册的视频(在 YouTube 上)。现在让我们仔细看看它在 Spring Cloud Function 中是如何工作的。
以下是 Spring Cloud Function 1.0 版本的一个应用程序示例,使用了熟悉的 `@Configuration` 和 `@Bean` 声明风格
@SpringBootApplication
public class DemoApplication {
@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
你可以通过将其与所有依赖项一起打包成 jar 文件并上传到 Amazon 来在 AWS Lambda(例如)中运行它。该项目还支持 Azure Functions 和 Apache OpenWhisk。其他无服务器提供商,例如 Oracle Fn 和 Riff,维护着自己的绑定。
你还可以通过在 classpath 中包含 `spring-cloud-function-starter-web` 来在应用程序自身的 HTTP 服务器中运行上面的应用。运行 main 方法将暴露一个端点,你可以使用该端点来调用那个 `uppercase` 函数。
$ curl localhost:8080 -d foo
FOO
1.0 版本中的 Web 适配器是使用 Spring MVC 实现的,因此你需要一个 Servlet 容器。在 Spring Cloud Function 2.0 中,你也可以使用 Webflux,并且默认服务器是 Netty(尽管如果你愿意,仍然可以使用 Servlet 容器)——只需包含 `spring-cloud-starter-function-webflux` 依赖项即可。功能是相同的,并且用户应用程序代码可以在两者中通用。
然而,在 2.0 版本中,用户应用程序代码可以重写为“函数式”形式,如下所示
@SpringBootConfiguration
public class DemoApplication
implements ApplicationContextInitializer<GenericApplicationContext> {
public static void main(String[] args) {
FunctionalSpringApplication.run(DemoApplication.class, args);
}
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean("demo", FunctionRegistration.class,
() -> new FunctionRegistration<>(uppercase())
.type(FunctionType.from(String.class).to(String.class)));
}
}
主要区别在于
主类是一个 `ApplicationContextInitializer`。
`@Bean` 方法已转换为调用 `context.registerBean()`
`@SpringBootApplication` 已被 `@SpringBootConfiguration` 替换,表示我们没有启用 Spring Boot 自动配置,但仍将该类标记为“入口点”。
Spring Boot 中的 `SpringApplication` 已被 Spring Cloud Function 的 `FunctionalSpringApplication`(它是其子类)替换。
你在 Spring Cloud Function 应用程序中注册的业务逻辑 Bean 类型是 `FunctionRegistration`。这是一个包装类,其中包含函数以及输入和输出类型的信息。在应用程序的 `@Bean` 形式中,这些信息可以通过反射获取,但在函数式 Bean 注册中,除非我们使用 `FunctionRegistration`,否则部分信息会丢失。
使用 `ApplicationContextInitializer` 和 `FunctionRegistration` 的另一种方法是让应用程序本身实现 `Function`(或 `Consumer` 或 `Supplier`)。例如(与上述等效)
@SpringBootConfiguration
public class DemoApplication implements Function<String, String> {
public static void main(String[] args) {
FunctionalSpringApplication.run(DemoApplication.class, args);
}
@Override
public String apply(String value) {
return value.toUpperCase();
}
}
添加一个独立的、类型为 `Function` 的类,并使用 `run()` 方法的另一种形式将其注册到 `SpringApplication` 中也是可行的。关键在于通过类声明在运行时获得泛型类型信息。
如果你添加 `spring-cloud-starter-function-webflux` 依赖,应用程序就可以在其自身的 HTTP 服务器中运行(目前与 MVC starter 不兼容,因为嵌入式 Servlet 容器的函数式形式尚未实现)。该应用程序在 AWS Lambda 或 Azure Functions 中也能正常运行,并且启动时间有了显著改进(如上图所示)。下图展示了另一张图中的启动时间(y 轴为启动时间,单位为秒)。
Spring Cloud Function 2.0 还提供了一些用于集成测试的实用工具,这些工具对于 Spring Boot 用户来说会非常熟悉。例如,这是一个用于测试上述应用程序 HTTP 服务器包装的集成测试示例。
@RunWith(SpringRunner.class)
@FunctionalSpringBootTest
@AutoConfigureWebTestClient
public class FunctionalTests {
@Autowired
private WebTestClient client;
@Test
public void words() throws Exception {
client.post().uri("/").body(Mono.just("foo"), String.class)
.exchange().expectStatus().isOk()
.expectBody(String.class).isEqualTo("FOO");
}
}
这个测试几乎与你为同一个应用程序的 `@Bean` 版本编写的测试完全相同——唯一的区别是使用了 `@FunctionalSpringBootTest` 注解,而不是常规的 `@SpringBootTest`。所有其他部分,比如 `@Autowired` 的 `WebTestClient`,都是标准的 Spring Boot 特性。
Spring Boot 与函数式 Bean 注册配合得很好——Spring Cloud Function 构建并运行在 Spring Boot 上——但 Spring Boot 中一些最有用的特性,即自动配置,都是以非函数式风格编写的。与整个 Spring Boot 相比,大多数 Spring Cloud Function 应用的范围相对较小,因此我们可以轻松地将其适应这些函数式 Bean 定义。如果你超出了这个有限的范围,可以通过切换回 `@Bean` 风格的配置或采用混合方法来扩展你的 Spring Cloud Function 应用。将类似的功能扩展到 Spring Boot 生态系统的其余部分还需要一些时间,但我们正在积极地开展这项工作。请尝试使用 Spring Cloud Function 2.0,如果有时间,请向我们提供一些反馈——GA 版本即将发布。