此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 spring-cloud-function 4.1.4spring-doc.cn

函数式 Bean 定义

Spring Cloud Function 支持需要快速启动的小型应用程序的“功能”样式的 bean 声明。bean 声明的函数式风格是 Spring Framework 5.0 的一个特性,在 5.1 中得到了显著的增强。spring-doc.cn

比较函数式 Bean 定义与传统 Bean 定义

下面是一个普通的 Spring Cloud Function 应用程序,其中包含 熟悉和声明样式:@Configuration@Beanspring-doc.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” 形式,如下所示:spring-doc.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.cn

  • 主类是一个 .ApplicationContextInitializerspring-doc.cn

  • 这些方法已转换为对@Beancontext.registerBean()spring-doc.cn

  • 已替换为 ,表示我们没有启用 Spring 引导自动配置,但仍将类标记为 “entry” 点”。@SpringBootApplication@SpringBootConfigurationspring-doc.cn

  • from Spring Boot 已替换为 from Spring Cloud 函数(它是一个 子类)。SpringApplicationFunctionalSpringApplicationspring-doc.cn

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

使用 and 的替代方法是使应用程序 本身实现(或 或 )。示例(相当于上述):ApplicationContextInitializerFunctionRegistrationFunctionConsumerSupplierspring-doc.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();
  }

}

如果您添加一个单独的独立类型类并将其注册 使用方法的替代形式。最主要的是,泛型 类型信息在运行时通过类声明提供。FunctionSpringApplicationrun()spring-doc.cn

假设您有spring-doc.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.cn

@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@EnableAutoConfigurationspring.functional.enabled=falsespring-doc.cn

功能可视化和控制

Spring Cloud Function 支持通过 Actuator 端点以及编程方式实现可用函数的可视化。FunctionCatalogspring-doc.cn

编程方式

要以编程方式查看应用程序上下文中可用的函数,您只需访问 .在那里你可以 查找获取目录大小、查找函数以及列出所有可用函数名称的方法。FunctionCatalogspring-doc.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
. . .

驱动器

由于 actuator 和 web 是可选的,因此您必须首先添加其中一个 web 依赖项,然后手动添加 actuator 依赖项。 下面的示例演示如何为 Web 框架添加依赖项:spring-doc.cn

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

以下示例演示如何为 WebFlux 框架添加依赖项:spring-doc.cn

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

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

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

您还必须通过设置以下属性来启用 Actuator 端点: 。functions--management.endpoints.web.exposure.include=functionsspring-doc.cn

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

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

您的输出应如下所示:spring-doc.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.cn

假设这是您的应用程序:spring-doc.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.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.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());
    }
}

此测试与您为同一应用程序的版本编写的测试几乎相同 - 唯一的区别 是批注,而不是常规的 .所有其他作品, 与 一样,是标准的 Spring Boot 功能。@Bean@FunctionalSpringBootTest@SpringBootTest@AutowiredTestRestTemplatespring-doc.cn

为了帮助正确依赖关系,以下是 POM 的摘录spring-doc.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.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>

或者,您可以仅使用 .例如:FunctionCatalogspring-doc.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");
	}

}