此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 spring-cloud-function 4.3.0spring-doc.cadn.net.cn

函数式 Bean 定义

Spring Cloud Function 支持需要快速启动的小型应用程序的“函数式”bean 声明。bean 声明的功能样式是 Spring Framework 5.0 的一个功能,在 5.1 中进行了重大增强。spring-doc.cadn.net.cn

比较函数式与传统 Bean 定义

这是一个普通的 Spring Cloud Function 应用程序,来自 熟悉@Configuration@Bean声明样式:spring-doc.cadn.net.cn

@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” form,如下所示:spring-doc.cadn.net.cn

@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)));
  }

}

主要区别是:spring-doc.cadn.net.cn

  • 主类是ApplicationContextInitializer.spring-doc.cadn.net.cn

  • @Bean方法已转换为对context.registerBean()spring-doc.cadn.net.cn

  • @SpringBootApplication已被替换为@SpringBootConfiguration表示我们没有启用 Spring 启动自动配置,但仍将类标记为“条目 点“。spring-doc.cadn.net.cn

  • SpringApplication来自 Spring Boot 的FunctionalSpringApplication来自 Spring Cloud 函数(它是 子类)。spring-doc.cadn.net.cn

在 Spring Cloud Function 应用中注册的业务逻辑 bean 类型为FunctionRegistration. 这是一个包装器,包含函数以及有关输入和输出类型的信息。在@Bean应用程序的形式,信息可以反射性地派生,但在功能 bean 注册中的一些 除非我们使用FunctionRegistration.spring-doc.cadn.net.cn

使用ApplicationContextInitializerFunctionRegistration就是要申请 本身实现Function(或ConsumerSupplier).示例(相当于上述):spring-doc.cadn.net.cn

@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()方法。最主要的是,通用的 类型信息在运行时可通过类声明获得。spring-doc.cadn.net.cn

@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()));
	}

}

您可以这样注册它:spring-doc.cadn.net.cn

@Override
public void initialize(GenericApplicationContext context) {
		context.registerBean("function", FunctionRegistration.class,
				() -> new FunctionRegistration<>(new CustomFunction()).type(CustomFunction.class));
}

功能 Bean 声明的局限性

与整个 Spring Boot 相比,大多数 Spring Cloud 函数应用程序的范围相对较小, 因此,我们能够轻松地将其调整到这些功能 bean 定义中。如果你走出这个有限的范围, 您可以通过切换回@Bean样式配置,或通过使用混合 方法。如果您想利用 Spring Boot 自动配置与外部数据存储集成, 例如,您需要使用@EnableAutoConfiguration.您的函数仍可以使用函数 声明(即“混合”样式),但在这种情况下,您需要显式关闭“完整” 功能模式“使用spring.functional.enabled=false以便 Spring Boot 可以收回控制权。spring-doc.cadn.net.cn

功能可视化和控制

Spring Cloud Function 支持可视化FunctionCatalog通过执行器端点以及编程方式。spring-doc.cadn.net.cn

程序化方式

要以编程方式查看应用程序上下文中可用的函数,您只需访问FunctionCatalog.在那里你可以 查找获取目录大小的方法,查找函数以及列出所有可用函数的名称。spring-doc.cadn.net.cn

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
. . .

驱动器

由于执行器和 Web 是可选的,因此必须首先添加其中一个 Web 依赖项,并手动添加执行器依赖项。以下示例显示如何添加 Web 框架的依赖项:spring-doc.cadn.net.cn

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
</dependency>

以下示例显示如何添加 WebFlux 框架的依赖项:spring-doc.cadn.net.cn

<dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

您可以按如下方式添加 Actuator 依赖项:spring-doc.cadn.net.cn

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

您还必须启用functions执行器端点,通过设置以下属性:--management.endpoints.web.exposure.include=functions.spring-doc.cadn.net.cn

访问以下 URL 以查看 FunctionCatalog 中的函数:<host>:<port>/actuator/functionsspring-doc.cadn.net.cn

curl http://localhost:8080/actuator/functions

您的输出应如下所示:spring-doc.cadn.net.cn

{"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 用户来说将非常熟悉。spring-doc.cadn.net.cn

假设这是您的应用程序:spring-doc.cadn.net.cn

@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 服务器的集成测试:spring-doc.cadn.net.cn

@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 定义样式时:spring-doc.cadn.net.cn

@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());
    }
}

此测试与您为@Bean同一应用程序的版本 - 唯一的区别是@FunctionalSpringBootTest注释,而不是常规的@SpringBootTest. 所有其他部分,就像@Autowired TestRestTemplate,是标准的 Spring Boot 功能。spring-doc.cadn.net.cn

为了帮助正确依赖,这里摘录自 POMspring-doc.cadn.net.cn

    <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.1.7-SNAPSHOT</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. 例如:spring-doc.cadn.net.cn

@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");
	}

}