宣布 Spring Cloud Function 3.0.0.M2

工程 | Oleg Zhurakousky | 2019年8月15日 | ...

我们很高兴宣布 Spring Cloud Function 3.0.0.M2 的第二个里程碑版本。

注意:Spring Cloud Function 3.0.0.M1 主要用于建立与 Spring Boot 2.2.x 的兼容性,因此未进行公告。

Spring Cloud Function 3.0.0.M2 模块可在 Spring Milestone 仓库中使用。

快速亮点

  • Spring Boot 2.2.x
  • 增强的部署器(需要单独的博客文章)

显著的功能和增强

函数元数(多个输入/输出)

此次里程碑引入的最大特性之一是支持具有多个输入和输出的函数。需要强调的是,这个特性只在响应式(reactive)场景下才有意义,在这种场景下,你可能希望将多个流传递给一个函数,以对这些流进行某种聚合/合并操作。对于常规情况,你可以随时使用某种类型的集合来传递多个参数。

为了以类型安全的方式表示多个输入/输出,以便受益于类型转换以及前面提到的其他特性,我们选择了 project reactorTuple 库,因为 Spring Cloud Function 从一开始就将其作为核心依赖。但是,未来我们也打算支持 BiFunction 以及 POJO 风格的函数,前提是我们能够通过某种约定来确定输入和输出的元数(arity)和类型。

虽然这个特性是新的,并且仍处于增强过程中,但它已经被几个内部项目使用,你也可以尝试一下。这是一个例子:

假设有以下函数:

@Bean
public Function<Tuple2<Flux<String>, Flux<Integer>>, Flux<?>[]> repeater() {
  return tuple -> {
    Flux<String> stringFlux = tuple.getT1();
    Flux<Integer> integerFlux = tuple.getT2();

    Flux<Integer> sharedIntFlux = integerFlux.publish().autoConnect(2);

    Flux<String> repeated = stringFlux
      .zipWith(sharedIntFlux)
      .flatMap(t -> 
            Flux.fromIterable(Collections.nCopies(t.getT2(), t.getT1())));

    Flux<Integer> sum = sharedIntFlux
	.buffer(3, 1)
	.map(l -> l.stream().mapToInt(Integer::intValue).sum());

    return new Flux[] { repeated, sum };
  };
}

你可以这样调用它:

Function<Tuple2<Flux<String>, Flux<Integer>>, Flux<?>[]> repeater = catalog.lookup("repeater");
Flux<String> stringStream = Flux.just("one", "two", "three");
Flux<Integer> intStream = Flux.just(3, 2, 1);
Flux<?>[] result = repeater.apply(Tuples.of(stringStream, intStream));
result[0].subscribe(System.out::println);
result[1].subscribe(System.out::println);

未来将有另一篇博客专门讨论这个主题。

编程风格选择 - 响应式、命令式

和以前一样,函数可以通过 project reactor 以命令式或响应式风格实现。然而,在以前的版本中,我们总是会对使用命令式风格实现的函数应用响应式转换。例如,Function<Foo, Foo> 会变成 Function<Flux<Foo>, Flux<Foo>>。在此版本发布后,情况不再是这样了。使用命令式方式实现的函数可以按原样(命令式)查找和调用,或者作为响应式等效项调用。例如,假设有以下配置:

@Bean
public Function<String, String> uppercase() {
	return v -> v.toUpperCase();
}

你可以按原样访问此函数:

Function<String, String> function = functionCatalog.lookup("uppercase");

或者作为响应式等效项:

Function<Flux<String>, Flux<String>> reactiveFunction = functionCatalog.lookup("uppercase");

Spring Cloud Function 会自动适应。

输入和输出的透明类型转换。

此里程碑带来的新特性之一是在函数核心层进行了透明的类型转换。虽然其中一些功能在 Web 适配器中已经存在,但现在它可以在函数调用级别使用,让任何类型的函数消费者(不仅仅是 Web)都能从中受益。此特性最主要的好处之一是在组合函数时体现(稍后将详细介绍)。例如,假设有以下函数:Function<Foo, Foo> foo()Function<Bar, Bar> bar() 组合为 foo|bar。在以前的版本中,由于一个函数的输出和另一个函数的输入之间存在类型不兼容,这将无法工作,但现在只要存在适当的转换策略,它就得到了支持。这些转换策略是标准的 Spring ConversionServiceMessageConverters。虽然我们仍在完善此功能并提供详细文档,但对于大多数情况(例如 JSON)有效的 ConversionServiceMessageConverters 已经默认初始化。

例如,假设有以下函数配置:

@Bean
public Function<Person, Person> uppercasePerson() {
  return person -> {
    return new Person(person.getName().toUpperCase(), person.getId());
  };
}

为了利用 MessageConverters,我们可以将此函数调用为 Function<Message<String>, Person>(或者以 byte[] 作为载荷),从而利用可用的 JSON MessageConverterString 转换为 Person(见下文)。

Function<Message<String>, Person> uppercasePerson = catalog.lookup("uppercasePerson");
Person person =  uppercasePerson.apply(MessageBuilder.withPayload("{\"name\":\"bill\",\"id\":2}").build()); 

请记住,对于使用响应式风格编写的函数,没有任何变化,并且应用了相同的转换策略

函数组合和适配;

虽然函数组合不是 Spring Cloud Function 的新特性,但在本次里程碑中得到了改进。

和以前一样,你可以通过 "|" 或 “,” 字符组合函数。

作为额外的优势,你可以组合具有不同编程风格的函数(例如,响应式和命令式),你可以组合SupplierFunctionSupplierConsumerFunctionConsumer 等等——我们会进行适配。你可以组合那些生产者函数的输出与消费者函数的输入不匹配的函数——我们会进行转换。未来将有另一篇博客专门讨论这个主题,并且我们也在完善文档。

下一步

一如既往,我们欢迎反馈和贡献,请通过 StackoverflowGitHub 与我们联系。

获取 Spring 新闻通讯

通过 Spring 新闻通讯保持联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件,只需一份简单的订阅。

了解更多

即将举行的活动

查看 Spring 社区所有即将举行的活动。

查看所有