此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 spring-cloud-function 4.1.4! |
函数式 Bean 定义
Spring Cloud Function 支持需要快速启动的小型应用程序的“功能”样式的 bean 声明。bean 声明的函数式风格是 Spring Framework 5.0 的一个特性,在 5.1 中得到了显著的增强。
比较函数式 Bean 定义与传统 Bean 定义
下面是一个普通的 Spring Cloud Function 应用程序,其中包含
熟悉和声明样式:@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);
}
}
现在是函数式 bean:用户应用程序代码可以重铸为 “functional” 形式,如下所示:
@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(FunctionTypeUtils.functionType(String.class, String.class)));
}
}
主要区别在于:
-
主类是一个 .
ApplicationContextInitializer
-
这些方法已转换为对
@Bean
context.registerBean()
-
已替换为 ,表示我们没有启用 Spring 引导自动配置,但仍将类标记为 “entry” 点”。
@SpringBootApplication
@SpringBootConfiguration
-
from Spring Boot 已替换为 from Spring Cloud 函数(它是一个 子类)。
SpringApplication
FunctionalSpringApplication
您在 Spring Cloud Function 应用程序中注册的业务逻辑 bean 的类型为 .
这是一个包装器,其中包含函数以及有关输入和输出类型的信息。在应用程序的形式中,该信息可以反射地派生,但在函数式 bean 注册中,一些
除非我们使用 .FunctionRegistration
@Bean
FunctionRegistration
使用 and 的替代方法是使应用程序
本身实现(或 或 )。示例(相当于上述):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
SpringApplication
run()
假设您有
@Component
public class CustomFunction implements Function<Flux<Foo>, Flux<Bar>> {
@Override
public Flux<Bar> apply(Flux<Foo> flux) {
return flux.map(foo -> new Bar("This is a Bar object from Foo value: " + foo.getValue()));
}
}
您可以按如下方式注册它:
@Override
public void initialize(GenericApplicationContext context) {
context.registerBean("function", FunctionRegistration.class,
() -> new FunctionRegistration<>(new CustomFunction()).type(CustomFunction.class));
}
函数式 Bean 声明的限制
与整个 Spring Boot 相比,大多数 Spring Cloud Function 应用程序的范围相对较小,
因此,我们能够轻松地将其适应这些函数式 bean 定义。如果您超出该限制范围,
您可以通过切换回样式配置或使用混合
方法。如果您想利用 Spring Boot 自动配置与外部数据存储集成,
例如,您需要使用 .您的函数仍然可以使用函数
声明(即 “hybrid” 样式),但在这种情况下,您需要显式关闭 “full
functional mode“,以便 Spring Boot 可以收回控制权。@Bean
@EnableAutoConfiguration
spring.functional.enabled=false
功能可视化和控制
Spring Cloud Function 支持通过 Actuator 端点以及编程方式实现可用函数的可视化。FunctionCatalog
编程方式
要以编程方式查看应用程序上下文中可用的函数,您只需访问 .在那里你可以
查找获取目录大小、查找函数以及列出所有可用函数名称的方法。FunctionCatalog
例如
FunctionCatalog functionCatalog = context.getBean(FunctionCatalog.class);
int size = functionCatalog.size(); // will tell you how many functions available in catalog
Set<String> names = functionCatalog.getNames(null); will list the names of all the Function, Suppliers and Consumers available in catalog
. . .
驱动器
由于 actuator 和 web 是可选的,因此您必须首先添加其中一个 web 依赖项,然后手动添加 actuator 依赖项。 下面的示例演示如何为 Web 框架添加依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
以下示例演示如何为 WebFlux 框架添加依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
您可以按如下方式添加 Actuator 依赖项:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
您还必须通过设置以下属性来启用 Actuator 端点: 。functions
--management.endpoints.web.exposure.include=functions
访问以下 URL 以查看 FunctionCatalog 中的函数:<host>:<port>/actuator/functions
例如
curl http://localhost:8080/actuator/functions
您的输出应如下所示:
{"charCounter":
{"type":"FUNCTION","input-type":"string","output-type":"integer"},
"logger":
{"type":"CONSUMER","input-type":"string"},
"functionRouter":
{"type":"FUNCTION","input-type":"object","output-type":"object"},
"words":
{"type":"SUPPLIER","output-type":"string"}. . .
测试功能应用程序
Spring Cloud Function 还具有一些 Spring Boot 用户非常熟悉的集成测试实用程序。
假设这是您的应用程序:
@SpringBootApplication
public class SampleFunctionApplication {
public static void main(String[] args) {
SpringApplication.run(SampleFunctionApplication.class, args);
}
@Bean
public Function<String, String> uppercase() {
return v -> v.toUpperCase();
}
}
以下是包装此应用程序的 HTTP 服务器的集成测试:
@SpringBootTest(classes = SampleFunctionApplication.class,
webEnvironment = WebEnvironment.RANDOM_PORT)
public class WebFunctionTests {
@Autowired
private TestRestTemplate rest;
@Test
public void test() throws Exception {
ResponseEntity<String> result = this.rest.exchange(
RequestEntity.post(new URI("/uppercase")).body("hello"), String.class);
System.out.println(result.getBody());
}
}
或者当使用函数 bean 定义样式时:
@FunctionalSpringBootTest
public class WebFunctionTests {
@Autowired
private TestRestTemplate rest;
@Test
public void test() throws Exception {
ResponseEntity<String> result = this.rest.exchange(
RequestEntity.post(new URI("/uppercase")).body("hello"), String.class);
System.out.println(result.getBody());
}
}
此测试与您为同一应用程序的版本编写的测试几乎相同 - 唯一的区别
是批注,而不是常规的 .所有其他作品,
与 一样,是标准的 Spring Boot 功能。@Bean
@FunctionalSpringBootTest
@SpringBootTest
@Autowired
TestRestTemplate
为了帮助正确依赖关系,以下是 POM 的摘录
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<relativePath/> <!-- lookup parent from repository -->
</parent>
. . . .
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
<version>4.2.0-RC1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
或者,您可以仅使用 .例如:FunctionCatalog
@FunctionalSpringBootTest
public class FunctionalTests {
@Autowired
private FunctionCatalog catalog;
@Test
public void words() {
Function<String, String> function = catalog.lookup(Function.class,
"uppercase");
assertThat(function.apply("hello")).isEqualTo("HELLO");
}
}