# WebFlux 支持
# WebFlux 支持
WebFlux Spring 集成模块(spring-integration-webflux
)允许以反应的方式执行 HTTP 请求和处理入站 HTTP 请求。
你需要在项目中包含此依赖项:
Maven
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-webflux</artifactId>
<version>5.5.9</version>
</dependency>
Gradle
compile "org.springframework.integration:spring-integration-webflux:5.5.9"
在非基于 Servlet 的服务器配置的情况下,必须包含io.projectreactor.netty:reactor-netty
依赖项。
WebFlux 支持由以下网关实现组成:WebFluxInboundEndpoint
和WebFluxRequestExecutingMessageHandler
。该支持完全基于 Spring WebFlux (opens new window)和项目反应堆 (opens new window)的基础。有关更多信息,请参见HTTP 支持,因为许多选项是在反应性和常规 HTTP 组件之间共享的。
# WebFlux 名称空间支持
Spring 集成提供了webflux
名称空间和相应的模式定义。要将其包含在配置中,请在应用程序上下文配置文件中添加以下名称空间声明:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-webflux="http://www.springframework.org/schema/integration/webflux"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
https://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/webflux
https://www.springframework.org/schema/integration/webflux/spring-integration-webflux.xsd">
...
</beans>
# WebFlux 入站组件
从版本 5.0 开始,提供了WebFluxInboundEndpoint
的WebHandler
实现。这个组件类似于基于 MVC 的HttpRequestHandlingEndpointSupport
,它通过新提取的BaseHttpInboundEndpoint
与该组件共享一些公共选项。它被用于 Spring WebFlux 反应环境(而不是 MVC)。下面的示例展示了 WebFlux 端点的一个简单实现:
爪哇 DSL
@Bean
public IntegrationFlow inboundChannelAdapterFlow() {
return IntegrationFlows
.from(WebFlux.inboundChannelAdapter("/reactivePost")
.requestMapping(m -> m.methods(HttpMethod.POST))
.requestPayloadType(ResolvableType.forClassWithGenerics(Flux.class, String.class))
.statusCodeFunction(m -> HttpStatus.ACCEPTED))
.channel(c -> c.queue("storeChannel"))
.get();
}
Kotlin DSL
@Bean
fun inboundChannelAdapterFlow() =
integrationFlow(
WebFlux.inboundChannelAdapter("/reactivePost")
.apply {
requestMapping { m -> m.methods(HttpMethod.POST) }
requestPayloadType(ResolvableType.forClassWithGenerics(Flux::class.java, String::class.java))
statusCodeFunction { m -> HttpStatus.ACCEPTED }
})
{
channel { queue("storeChannel") }
}
爪哇
@Configuration
@EnableWebFlux
@EnableIntegration
public class ReactiveHttpConfiguration {
@Bean
public WebFluxInboundEndpoint simpleInboundEndpoint() {
WebFluxInboundEndpoint endpoint = new WebFluxInboundEndpoint();
RequestMapping requestMapping = new RequestMapping();
requestMapping.setPathPatterns("/test");
endpoint.setRequestMapping(requestMapping);
endpoint.setRequestChannelName("serviceChannel");
return endpoint;
}
@ServiceActivator(inputChannel = "serviceChannel")
String service() {
return "It works!";
}
}
XML
<int-webflux:inbound-gateway request-channel="requests" path="/sse">
<int-webflux:request-mapping produces="text/event-stream"/>
</int-webflux:inbound-gateway>
该配置类似于HttpRequestHandlingEndpointSupport
(在示例之前提到),只是我们使用@EnableWebFlux
将 WebFlux 基础架构添加到我们的集成应用程序中。此外,WebFluxInboundEndpoint
通过使用反作用 HTTP 服务器实现提供的基于按需的能力,对下游流执行sendAndReceive
操作。
应答部分也是非阻塞的,并且基于内部FutureReplyChannel ,该内部Mono 被平映到一个响应Mono 以进行按需解析。 |
---|
你可以使用自定义ServerCodecConfigurer
、RequestedContentTypeResolver
甚至ReactiveAdapterRegistry
来配置WebFluxInboundEndpoint
。后者提供了一种机制,你可以使用该机制以任何反应类型返回回复:reactorFlux
,rxjavaObservable
,Flowable
,以及其他类型。通过这种方式,我们可以使用 Spring 集成组件实现服务器发送事件 (opens new window)场景,如下例所示:
爪哇 DSL
@Bean
public IntegrationFlow sseFlow() {
return IntegrationFlows
.from(WebFlux.inboundGateway("/sse")
.requestMapping(m -> m.produces(MediaType.TEXT_EVENT_STREAM_VALUE)))
.handle((p, h) -> Flux.just("foo", "bar", "baz"))
.get();
}
Kotlin DSL
@Bean
fun sseFlow() =
integrationFlow(
WebFlux.inboundGateway("/sse")
.requestMapping(m -> m.produces(MediaType.TEXT_EVENT_STREAM_VALUE)))
{
handle { (p, h) -> Flux.just("foo", "bar", "baz") }
}
Java
@Bean
public WebFluxInboundEndpoint webfluxInboundGateway() {
WebFluxInboundEndpoint endpoint = new WebFluxInboundEndpoint();
RequestMapping requestMapping = new RequestMapping();
requestMapping.setPathPatterns("/sse");
requestMapping.setProduces(MediaType.TEXT_EVENT_STREAM_VALUE);
endpoint.setRequestMapping(requestMapping);
endpoint.setRequestChannelName("requests");
return endpoint;
}
XML
<int-webflux:inbound-channel-adapter id="reactiveFullConfig" channel="requests"
path="test1"
auto-startup="false"
phase="101"
request-payload-type="byte[]"
error-channel="errorChannel"
payload-expression="payload"
supported-methods="PUT"
status-code-expression="'202'"
header-mapper="headerMapper"
codec-configurer="codecConfigurer"
reactive-adapter-registry="reactiveAdapterRegistry"
requested-content-type-resolver="requestedContentTypeResolver">
<int-webflux:request-mapping headers="foo"/>
<int-webflux:cross-origin origin="foo" method="PUT"/>
<int-webflux:header name="foo" expression="'foo'"/>
</int-webflux:inbound-channel-adapter>
有关更多可能的配置选项,请参见请求映射支持和跨源资源共享支持。
当请求主体为空或payloadExpression
返回null
时,请求参数(MultiValueMap<String, String>
)用于处理目标消息的payload
。
# 有效载荷验证
从版本 5.2 开始,WebFluxInboundEndpoint
可以配置为Validator
。与HTTP 支持中的 MVC 验证不同,它用于验证Publisher
中的元素,在执行回退和payloadExpression
函数之前,Publisher
已将请求转换为该元素。该框架不能假设在构建最终有效负载之后Publisher
对象的复杂程度。如果需要限制最终有效负载(或其Publisher
元素)的验证可见性,则验证应该向下游进行,而不是向 WebFlux 端点进行。有关更多信息,请参见 Spring WebFlux文件 (opens new window)。使用IntegrationWebExchangeBindException
(一个WebExchangeBindException
扩展)拒绝无效的负载,该扩展包含所有验证Errors
。请参阅 Spring Framework参考手册 (opens new window)中有关验证的更多内容。
# WebFlux 出站组件
WebFluxRequestExecutingMessageHandler
(从版本 5.0 开始)实现类似于HttpRequestExecutingMessageHandler
。它使用了 Spring Framework WebFlux 模块中的WebClient
。要对其进行配置,请定义一个类似于以下内容的 Bean:
Java DSL
@Bean
public IntegrationFlow outboundReactive() {
return f -> f
.handle(WebFlux.<MultiValueMap<String, String>>outboundGateway(m ->
UriComponentsBuilder.fromUriString("http://localhost:8080/foo")
.queryParams(m.getPayload())
.build()
.toUri())
.httpMethod(HttpMethod.GET)
.expectedResponseType(String.class));
}
Kotlin DSL
@Bean
fun outboundReactive() =
integrationFlow {
handle(
WebFlux.outboundGateway<MultiValueMap<String, String>>({ m ->
UriComponentsBuilder.fromUriString("http://localhost:8080/foo")
.queryParams(m.getPayload())
.build()
.toUri()
})
.httpMethod(HttpMethod.GET)
.expectedResponseType(String::class.java)
)
}
Java
@ServiceActivator(inputChannel = "reactiveHttpOutRequest")
@Bean
public WebFluxRequestExecutingMessageHandler reactiveOutbound(WebClient client) {
WebFluxRequestExecutingMessageHandler handler =
new WebFluxRequestExecutingMessageHandler("http://localhost:8080/foo", client);
handler.setHttpMethod(HttpMethod.POST);
handler.setExpectedResponseType(String.class);
return handler;
}
XML
<int-webflux:outbound-gateway id="reactiveExample1"
request-channel="requests"
url="http://localhost/test"
http-method-expression="headers.httpMethod"
extract-request-payload="false"
expected-response-type-expression="payload"
charset="UTF-8"
reply-timeout="1234"
reply-channel="replies"/>
<int-webflux:outbound-channel-adapter id="reactiveExample2"
url="http://localhost/example"
http-method="GET"
channel="requests"
charset="UTF-8"
extract-payload="false"
expected-response-type="java.lang.String"
order="3"
auto-startup="false"/>
WebClient``exchange()
操作返回一个Mono<ClientResponse>
,将其映射(通过使用几个Mono.map()
步骤)到一个AbstractIntegrationMessageBuilder
作为WebFluxRequestExecutingMessageHandler
的输出。连同ReactiveChannel
作为outputChannel
,Mono<ClientResponse>
评估将被推迟,直到进行下游订阅。否则,它将被视为async
模式,并且对于来自WebFluxRequestExecutingMessageHandler
的异步回复,将Mono
响应调整为SettableListenableFuture
。输出消息的目标负载取决于WebFluxRequestExecutingMessageHandler
配置。setExpectedResponseType(Class<?>)
或setExpectedResponseTypeExpression(Expression)
标识响应主体元素转换的目标类型。如果replyPayloadToFlux
被设置为true
,则响应主体将转换为Flux
,并为每个元素提供expectedResponseType
,然后将Flux
作为下游的有效负载发送。之后,你可以使用splitter以反应式的方式迭代这个Flux
。
此外,可以将BodyExtractor<?, ClientHttpResponse>
注入到WebFluxRequestExecutingMessageHandler
而不是expectedResponseType
和replyPayloadToFlux
属性中。它可以用于对ClientHttpResponse
的低级访问以及对 body 和 HTTP 头转换的更多控制。 Spring 集成提供了ClientHttpResponseBodyExtractor
作为标识函数来产生(下游)整个ClientHttpResponse
和任何其他可能的自定义逻辑。
从版本 5.2 开始,WebFluxRequestExecutingMessageHandler
支持反应式Publisher
、Resource
和MultiValueMap
类型作为请求消息有效负载。内部使用相应的BodyInserter
来将其填充到WebClient.RequestBodySpec
中。当有效负载是反应性的Publisher
时,可以使用配置的publisherElementType
或publisherElementTypeExpression
来确定发布者元素类型的类型。表达式必须解析为Class<?>
,String
,这将解析为目标Class<?>
或ParameterizedTypeReference
。
从版本 5.5 开始,WebFluxRequestExecutingMessageHandler
公开了一个extractResponseBody
标志(默认情况下是true
),以仅返回响应主体,或返回整个ResponseEntity
作为回复消息有效负载,而不依赖于所提供的expectedResponseType
或replyPayloadToFlux
。如果ResponseEntity
中不存在主体,则忽略此标志,并返回整个ResponseEntity
。
有关更多可能的配置选项,请参见HTTP 出站组件。
# WebFlux 标头映射
由于 WebFlux 组件完全基于 HTTP 协议,因此在 HTTP 头映射中没有区别。参见HTTP 头映射,以获得更多用于映射标头的可能选项和组件。