对于最新稳定版本,请使用Spring Framework 7.0.1spring-doc.cadn.net.cn

RSocket

本节介绍了 Spring Framework 对 RSocket 协议的支持。spring-doc.cadn.net.cn

概述

RSocket 是一种用于 TCP 上的多路复用双工通信的应用协议, WebSocket 及其他字节流传输,使用以下交互之一 模型:spring-doc.cadn.net.cn

一旦初始连接建立,“客户端”与“服务器”的区别将消失,因为 两侧变得对称,且每一方都可以启动上述其中一种相互作用。 这就是为什么协议中将参与方称为“请求方”和“响应方” 上述交互被称为“请求流”或简称“请求”。spring-doc.cadn.net.cn

以下是RSocket协议的主要功能和优势:spring-doc.cadn.net.cn

  • 跨网络边界的响应式流语义——针对以请求请求流渠道,背压信号 请求者与响应者之间的移动,允许请求者在 源头,从而减少对网络层拥塞控制的依赖,以及 用于网络层级或任何层级的缓冲。spring-doc.cadn.net.cn

  • 请求限速——该功能被称为“租赁”,来源于租赁框架 可以从两端发送,以限制对方允许的总请求数 在一定时间内。租约会定期续签。spring-doc.cadn.net.cn

  • 会话恢复——这是为失去连接而设计的,需要某种状态 需要维护。状态管理对应用程序透明,运行良好 结合背压,可以尽量停止生产并减少 所需的州政府数量。spring-doc.cadn.net.cn

  • 大消息的碎片化和重新组装。spring-doc.cadn.net.cn

  • 保持生命(心跳)。spring-doc.cadn.net.cn

RSocket 有多种语言实现Java 库构建在 Project Reactor, 以及用于运输的反应堆Netty。那就是说 你应用中来自反应流发布者的信号是透明传播的 通过RSocket跨网络传输。spring-doc.cadn.net.cn

议定书

RSocket的一个优点是它在导线上具有明确的行为,并且 易于阅读的规范以及一些协议扩展。因此,它就是 阅读规范是个好主意,独立于语言实现和更高层次 框架 API。本节提供简明概述,以建立一些背景。spring-doc.cadn.net.cn

最初客户端通过某种低级别流式传输连接到服务器,例如 作为TCP或WebSocket,并发送设置帧对服务器进行参数设置 连接。spring-doc.cadn.net.cn

服务器可能会拒绝设置但通常是在发送完(针对客户端)之后 并且(对服务器而言)收到,双方都可以开始发出请求,除非设置表示使用租赁语义来限制请求数量,在这种情况下 双方都必须等待租赁从另一端框架允许提出请求。spring-doc.cadn.net.cn

一旦建立连接,双方都可以通过其中一个 框架REQUEST_RESPONSE,REQUEST_STREAM,REQUEST_CHANNELREQUEST_FNF.每一个 这些帧传递请求者向响应者发送一条消息。spring-doc.cadn.net.cn

随后,响应者可以返回有效载荷带有响应消息的帧,以及在 之REQUEST_CHANNEL请求者也可发送有效载荷请求更多的帧 消息。spring-doc.cadn.net.cn

当请求涉及如请求流渠道, 响应者必须尊重请求者的请求信号。需求表达为 消息数量。初始需求定义为REQUEST_STREAMREQUEST_CHANNEL框架。后续需求通过以下方式来表示REQUEST_N框架。spring-doc.cadn.net.cn

双方还可以通过METADATA_PUSH框架,不 涉及任何个人请求,而是整个连接。spring-doc.cadn.net.cn

RSocket 消息包含数据和元数据。元数据可以用来发送路由,a 安全Tokens等。数据和元数据的格式可以不同。每个哑剧类型 在设置对给定连接上的所有请求进行帧和应用。spring-doc.cadn.net.cn

虽然所有消息都可以有元数据,但通常像路由这样的元数据是针对每个请求的 因此只包含在请求的第一条消息中,即与其中一个帧一起REQUEST_RESPONSE,REQUEST_STREAM,REQUEST_CHANNELREQUEST_FNF.spring-doc.cadn.net.cn

协议扩展定义了用于应用的常用元数据格式:spring-doc.cadn.net.cn

Java 实现

RSocket 的 Java 实现基于 Project Reactor。TCP和WebSocket的传输方式有 建造于Reactor Netty之上。作为反应流 Reactor 简化了实现该协议的工作。对于应用来说,是 自然而然地适合使用。通量采用声明式运算符和透明背板 压力支持。spring-doc.cadn.net.cn

RSocket Java 的 API 故意设计得极简和基础。它专注于协议 保留应用程序编程模型(例如 RPC 代码生成与其他模型)作为 更高层级的独立关注。spring-doc.cadn.net.cn

主合同 io.rsocket.RSocket表示对 单条信息,通量一条消息流,以及io.rsocket.有效载荷实际 消息,并以字节缓冲区的形式访问数据和元数据。这RSocket使用契约 对称。申请时,应用程序会被赋予RSocket表演 请求。响应时,应用程序实现了RSocket处理请求。spring-doc.cadn.net.cn

这并不是一个详尽的介绍。大多数情况下,春季申请 无需直接使用其API。不过,看看或做实验可能很重要 与 RSocket 独立于 Spring 发行。RSocket Java 仓库包含多个示例应用, 展示其API和协议特性。spring-doc.cadn.net.cn

春季支持

春季消息模块包含以下内容:spring-doc.cadn.net.cn

春网模包含编码器译码器如 Jackson 这样的实现 CBOR/JSON 和 Protobuf,这些 RSocket 应用很可能需要。它还包含路径模式解析器可以插入以实现高效的路由匹配。spring-doc.cadn.net.cn

Spring Boot 2.2 支持通过 TCP 或 WebSocket 搭建 RSocket 服务器,包括 在WebFlux服务器上通过WebSocket暴露RSocket的选项。还有客户端 支持与自动配置RSocketRequester.BuilderRocket策略. 更多细节请参见Spring Boot参考文献中的RSocket部分spring-doc.cadn.net.cn

Spring Security 5.2 提供 RSocket 支持。spring-doc.cadn.net.cn

Spring Integration 5.2 提供了与 RSocket 交互的入站和出站网关 客户端和服务器。更多详情请参见 Spring Integration 参考手册。spring-doc.cadn.net.cn

Spring Cloud Gateway 支持 RSocket 连接。spring-doc.cadn.net.cn

RSocketRequester

RSocketRequester提供流畅的 API 以执行 RSocket 请求,接受 和 返回数据和元数据对象,而非低级别数据缓冲区。它可以使用 对称地,可以从客户端发出请求,也可以从服务器发出请求。spring-doc.cadn.net.cn

客户端请求者

获得一个RSocketRequester客户端是连接到服务器,涉及 发送 RSocket设置框架内的连接设置。RSocketRequester提供 帮助准备io.rsocket.core.RSocketConnector包括连接 为设置框架。spring-doc.cadn.net.cn

这是使用默认设置连接的最基本方式:spring-doc.cadn.net.cn

RSocketRequester requester = RSocketRequester.builder().tcp("localhost", 7000);

URI url = URI.create("https://example.org:8080/rsocket");
RSocketRequester requester = RSocketRequester.builder().webSocket(url);
val requester = RSocketRequester.builder().tcp("localhost", 7000)

URI url = URI.create("https://example.org:8080/rsocket");
val requester = RSocketRequester.builder().webSocket(url)

上述内容立刻并不能产生联系。当请求发出时,共享连接是 透明地建立并被使用。spring-doc.cadn.net.cn

连接设置

RSocketRequester.Builder提供以下功能以自定义首字母设置框架:spring-doc.cadn.net.cn

对于数据,默认的 mime 类型是从第一个配置的译码器.为 元数据,默认的 MIME 类型是复合元数据,允许多个 每个请求的元数据值和 MIME 类型对。通常两者都不需要更换。spring-doc.cadn.net.cn

数据和元数据设置框架是可选的。在服务器端,可以使用@ConnectMapping方法来处理 连接与内容设置框架。元数据可用于连接 安全级别。spring-doc.cadn.net.cn

策略

RSocketRequester.Builder接受Rocket策略来配置请求者。 你需要用它来提供数据的(反)序列化编码器和解码器 元数据值。默认情况下,只能使用以下的基本编解码器Spring芯字符串,字节[]字节缓冲区已注册。 添加春网提供更多访问权限可注册如下:spring-doc.cadn.net.cn

RSocketStrategies strategies = RSocketStrategies.builder()
	.encoders(encoders -> encoders.add(new Jackson2CborEncoder()))
	.decoders(decoders -> decoders.add(new Jackson2CborDecoder()))
	.build();

RSocketRequester requester = RSocketRequester.builder()
	.rsocketStrategies(strategies)
	.tcp("localhost", 7000);
val strategies = RSocketStrategies.builder()
		.encoders { it.add(Jackson2CborEncoder()) }
		.decoders { it.add(Jackson2CborDecoder()) }
		.build()

val requester = RSocketRequester.builder()
		.rsocketStrategies(strategies)
		.tcp("localhost", 7000)

Rocket策略设计用于重复使用。在某些情况下,例如客户端和服务器同一应用中,可能更倾向于在 Spring 配置中声明。spring-doc.cadn.net.cn

客户响应者

RSocketRequester.Builder可用于配置响应者,以应对来自 服务器。spring-doc.cadn.net.cn

你可以使用带注释的处理器来进行客户端响应,基于相同的服务器上的基础设施,但程序注册方式如下:spring-doc.cadn.net.cn

RSocketStrategies strategies = RSocketStrategies.builder()
	.routeMatcher(new PathPatternRouteMatcher())  (1)
	.build();

SocketAcceptor responder =
	RSocketMessageHandler.responder(strategies, new ClientHandler()); (2)

RSocketRequester requester = RSocketRequester.builder()
	.rsocketConnector(connector -> connector.acceptor(responder)) (3)
	.tcp("localhost", 7000);
1 路径模式路由匹配器如果春网存在,以实现高效的路由匹配。
2 从一个类创建响应器,满足@MessageMapping和/或@ConnectMapping方法。
3 登记响应者。
val strategies = RSocketStrategies.builder()
		.routeMatcher(PathPatternRouteMatcher())  (1)
		.build()

val responder =
	RSocketMessageHandler.responder(strategies, new ClientHandler()); (2)

val requester = RSocketRequester.builder()
		.rsocketConnector { it.acceptor(responder) } (3)
		.tcp("localhost", 7000)
1 路径模式路由匹配器如果春网存在,以实现高效的路由匹配。
2 从一个类创建响应器,满足@MessageMapping和/或@ConnectMapping方法。
3 登记响应者。

请注意,上述仅是一个为程序化客户端注册设计的快捷方式 反应。 对于替代场景,比如客户端响应器处于Spring配置,你仍然可以声明RSocketMessageHandler作为春季豆,然后按以下方式涂抹:spring-doc.cadn.net.cn

ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);

RSocketRequester requester = RSocketRequester.builder()
	.rsocketConnector(connector -> connector.acceptor(handler.responder()))
	.tcp("localhost", 7000);
import org.springframework.beans.factory.getBean

val context: ApplicationContext = ...
val handler = context.getBean<RSocketMessageHandler>()

val requester = RSocketRequester.builder()
		.rsocketConnector { it.acceptor(handler.responder()) }
		.tcp("localhost", 7000)

对于上述情况,你可能还需要使用setHandlerPredicateRSocketMessageHandler自 切换到另一种策略来检测客户端响应者,例如基于自定义注释,如@RSocketClientResponder与默认的比较@Controller. 这 在客户端和服务器,或多个客户端同时存在的场景中是必要的 应用。spring-doc.cadn.net.cn

另请参见注释响应器,了解更多编程模型。spring-doc.cadn.net.cn

高深

RSocketRequesterBuilder提供回调以暴露底层io.rsocket.core.RSocketConnector关于保持活态的进一步配置选项间隔、会话恢复、拦截器等。你可以配置选项在该级别如下:spring-doc.cadn.net.cn

RSocketRequester requester = RSocketRequester.builder()
	.rsocketConnector(connector -> {
		// ...
	})
	.tcp("localhost", 7000);
val requester = RSocketRequester.builder()
		.rsocketConnector {
			//...
		}
		.tcp("localhost", 7000)

服务器请求器

从服务器向连接的客户端发出请求,关键是从服务器获得连接客户端的请求器。spring-doc.cadn.net.cn

《注释回答者》中,@ConnectMapping@MessageMapping方法支持一个RSocketRequester论点。 用它来访问连接的请求者。请记住记住@ConnectMapping方法本质上是设置帧必须在请求开始前处理。因此,最开始的请求必须与处理解耦。 例如:spring-doc.cadn.net.cn

@ConnectMapping
Mono<Void> handle(RSocketRequester requester) {
	requester.route("status").data("5")
		.retrieveFlux(StatusReport.class)
		.subscribe(bar -> { (1)
			// ...
		});
	return ... (2)
}
1 请求是异步启动的,独立于处理。
2 执行处理和返回补全单<虚空>.
@ConnectMapping
suspend fun handle(requester: RSocketRequester) {
	GlobalScope.launch {
		requester.route("status").data("5").retrieveFlow<StatusReport>().collect { (1)
			// ...
		}
	}
	/// ... (2)
}
1 请求是异步启动的,独立于处理。
2 在悬挂功能中执行作。

请求

一旦你有了客户端服务器请求者,你可以按以下方式提出请求:spring-doc.cadn.net.cn

ViewBox viewBox = ... ;

Flux<AirportLocation> locations = requester.route("locate.radars.within") (1)
		.data(viewBox) (2)
		.retrieveFlux(AirportLocation.class); (3)
1 指定一条路由,包含在请求消息的元数据中。
2 为请求消息提供数据。
3 声明预期的回应。
val viewBox: ViewBox = ...

val locations = requester.route("locate.radars.within") (1)
		.data(viewBox) (2)
		.retrieveFlow<AirportLocation>() (3)
1 指定一条路由,包含在请求消息的元数据中。
2 为请求消息提供数据。
3 声明预期的回应。

交互类型可通过输入的基数隐式确定,且 输出。 上述例子是一个请求流因为发送一个值,然后接收到一串数值。大多数情况下,只要输入和输出的选择符合RSocket交互类型以及输入和响应者预期的输出类型。唯一无效组合的例子是多对一。spring-doc.cadn.net.cn

data(对象)方法也接受任何响应式流发行人包括通量以及注册在ReactiveAdapter注册表. 对于多值发行人通量这会产生相同类型的值,考虑使用其中一种超载数据避免出现类型检查和的方法编码器查找每个元素:spring-doc.cadn.net.cn

data(Object producer, Class<?> elementClass);
data(Object producer, ParameterizedTypeReference<?> elementTypeRef);

data(对象)此步骤为可选。对于不发送数据的请求,跳过此步骤:spring-doc.cadn.net.cn

Mono<AirportLocation> location = requester.route("find.radar.EWR"))
	.retrieveMono(AirportLocation.class);
import org.springframework.messaging.rsocket.retrieveAndAwait

val location = requester.route("find.radar.EWR")
	.retrieveAndAwait<AirportLocation>()

如果使用复合元数据(默认),并且值被注册支持,则可以添加额外的元数据值编码器. 例如:spring-doc.cadn.net.cn

String securityToken = ... ;
ViewBox viewBox = ... ;
MimeType mimeType = MimeType.valueOf("message/x.rsocket.authentication.bearer.v0");

Flux<AirportLocation> locations = requester.route("locate.radars.within")
		.metadata(securityToken, mimeType)
		.data(viewBox)
		.retrieveFlux(AirportLocation.class);
import org.springframework.messaging.rsocket.retrieveFlow

val requester: RSocketRequester = ...

val securityToken: String = ...
val viewBox: ViewBox = ...
val mimeType = MimeType.valueOf("message/x.rsocket.authentication.bearer.v0")

val locations = requester.route("locate.radars.within")
		.metadata(securityToken, mimeType)
		.data(viewBox)
		.retrieveFlow<AirportLocation>()

火灾即忘使用以下发送()返回的方法单<虚空>. 注意仅表示消息已成功发送,而非已处理。spring-doc.cadn.net.cn

元数据推送使用以下sendMetadata()方法单<虚空>返回价值。spring-doc.cadn.net.cn

注释响应者

RSocket 响应器可以实现为@MessageMapping@ConnectMapping方法。@MessageMapping方法处理单个请求,当@ConnectMapping方法处理连接级事件(设置和元数据推送)。支持带注释的响应器对称地响应,既可从服务器端响应,也可以从客户端响应。spring-doc.cadn.net.cn

服务器响应器

要在服务器端使用带注释的响应器,添加RSocketMessageHandler敬你的泉水 检测配置@ControllerBeans@MessageMapping@ConnectMapping方法:spring-doc.cadn.net.cn

@Configuration
static class ServerConfig {

	@Bean
	public RSocketMessageHandler rsocketMessageHandler() {
		RSocketMessageHandler handler = new RSocketMessageHandler();
		handler.routeMatcher(new PathPatternRouteMatcher());
		return handler;
	}
}
@Configuration
class ServerConfig {

	@Bean
	fun rsocketMessageHandler() = RSocketMessageHandler().apply {
		routeMatcher = PathPatternRouteMatcher()
	}
}

然后通过Java RSocket API启动RSocket服务器,插入RSocketMessageHandler回答者如下:spring-doc.cadn.net.cn

ApplicationContext context = ... ;
RSocketMessageHandler handler = context.getBean(RSocketMessageHandler.class);

CloseableChannel server =
	RSocketServer.create(handler.responder())
		.bind(TcpServerTransport.create("localhost", 7000))
		.block();
import org.springframework.beans.factory.getBean

val context: ApplicationContext = ...
val handler = context.getBean<RSocketMessageHandler>()

val server = RSocketServer.create(handler.responder())
		.bind(TcpServerTransport.create("localhost", 7000))
		.awaitSingle()

RSocketMessageHandler默认支持复合路由元数据。如果你需要切换到 A,可以设置它的 MetadataExtractor 不同的哑剧类型或寄存器,额外的元数据模拟类型。spring-doc.cadn.net.cn

你需要设置编码器译码器元数据和数据所需的实例 支持格式。你很可能需要春网用于编解码器实现的模块。spring-doc.cadn.net.cn

默认情况下SimpleRouteMatcher用于匹配路由,通过以下方式蚁径匹配器. 我们建议插入路径模式路由匹配器春网为 高效的路线匹配。RSocket 路由可以是层级的,但不是 URL 路径。 两个路由匹配器默认都设置为使用“.”作为分隔符,且没有URL。 解码方式类似于HTTP URL。spring-doc.cadn.net.cn

RSocketMessageHandler可以通过以下方式配置Rocket策略这可能有用,如果 你需要在同一进程中,客户端和服务器之间共享配置:spring-doc.cadn.net.cn

@Configuration
static class ServerConfig {

	@Bean
	public RSocketMessageHandler rsocketMessageHandler() {
		RSocketMessageHandler handler = new RSocketMessageHandler();
		handler.setRSocketStrategies(rsocketStrategies());
		return handler;
	}

	@Bean
	public RSocketStrategies rsocketStrategies() {
		return RSocketStrategies.builder()
			.encoders(encoders -> encoders.add(new Jackson2CborEncoder()))
			.decoders(decoders -> decoders.add(new Jackson2CborDecoder()))
			.routeMatcher(new PathPatternRouteMatcher())
			.build();
	}
}
@Configuration
class ServerConfig {

	@Bean
	fun rsocketMessageHandler() = RSocketMessageHandler().apply {
		rSocketStrategies = rsocketStrategies()
	}

	@Bean
	fun rsocketStrategies() = RSocketStrategies.builder()
			.encoders { it.add(Jackson2CborEncoder()) }
			.decoders { it.add(Jackson2CborDecoder()) }
			.routeMatcher(PathPatternRouteMatcher())
			.build()
}

客户响应者

客户端的注释响应器需要在RSocketRequester.Builder.详情请参见客户响应者spring-doc.cadn.net.cn

@MessageMapping

一旦服务器客户端响应器配置就位,@MessageMapping方法可采用如下:spring-doc.cadn.net.cn

@Controller
public class RadarsController {

	@MessageMapping("locate.radars.within")
	public Flux<AirportLocation> radars(MapRequest request) {
		// ...
	}
}
@Controller
class RadarsController {

	@MessageMapping("locate.radars.within")
	fun radars(request: MapRequest): Flow<AirportLocation> {
		// ...
	}
}

以上内容@MessageMapping方法响应请求-流交互,满足 路由“locate.radars.within”。它支持灵活的方法签名,并可选 使用以下方法论元:spring-doc.cadn.net.cn

方法论元 描述

@Payloadspring-doc.cadn.net.cn

请求的有效载荷。这可以是异步类型的具体值,比如通量.spring-doc.cadn.net.cn

注意:注释的使用是可选的。一个不是简单类型的方法参数 且不是其他支持的论元,假设为预期有效载荷。spring-doc.cadn.net.cn

RSocketRequesterspring-doc.cadn.net.cn

请求者,用于向远程端提出请求。spring-doc.cadn.net.cn

@DestinationVariablespring-doc.cadn.net.cn

基于映射模式中的变量从路由中提取的值,例如:@MessageMapping(“find.radar.{id}“).spring-doc.cadn.net.cn

@Headerspring-doc.cadn.net.cn

MetadataExtractor 描述的提取数据值注册。spring-doc.cadn.net.cn

@Headers Map<String,对象>spring-doc.cadn.net.cn

所有元数据值均注册用于提取,均为MetadataExtractor所述。spring-doc.cadn.net.cn

返回值预期为一个或多个被序列化为响应的对象 负载。这可以是异步类型,比如通量,一个具体值,或者 也无效或是无值异步类型,如单<虚空>.spring-doc.cadn.net.cn

RSocket交互类型使得@MessageMapping方法支持由 确定 输入的基数(即@Payload参数)和输出的参数,其中 基数意味着以下内容:spring-doc.cadn.net.cn

基数 描述

1spring-doc.cadn.net.cn

可以是显式值,也可以是单值异步类型,例如单核细胞增<症>.spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

多值异步类型,如Flux<T>.spring-doc.cadn.net.cn

0spring-doc.cadn.net.cn

对于输入,这意味着该方法没有@Payload论点。spring-doc.cadn.net.cn

输出为无效或是无值异步类型,如单<虚空>.spring-doc.cadn.net.cn

下表显示了所有输入和输出基数组合及其对应的 互动类型:spring-doc.cadn.net.cn

输入基数 输出基数 交互类型

0, 1spring-doc.cadn.net.cn

0spring-doc.cadn.net.cn

发射后遗忘,请求-响应spring-doc.cadn.net.cn

0, 1spring-doc.cadn.net.cn

1spring-doc.cadn.net.cn

请求-响应spring-doc.cadn.net.cn

0, 1spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

请求流spring-doc.cadn.net.cn

spring-doc.cadn.net.cn

0,1,多spring-doc.cadn.net.cn

请求通道spring-doc.cadn.net.cn

@RSocketExchange

作为替代方案@MessageMapping,你也可以用@RSocketExchange方法。这些方法在 RSocket 接口上声明,并可作为请求者使用RSocketServiceProxyFactory或者由响应者实现。spring-doc.cadn.net.cn

例如,作为响应者处理请求:spring-doc.cadn.net.cn

public interface RadarsService {

	@RSocketExchange("locate.radars.within")
	Flux<AirportLocation> radars(MapRequest request);
}

@Controller
public class RadarsController implements RadarsService {

	public Flux<AirportLocation> radars(MapRequest request) {
		// ...
	}
}
interface RadarsService {

	@RSocketExchange("locate.radars.within")
	fun radars(request: MapRequest): Flow<AirportLocation>
}

@Controller
class RadarsController : RadarsService {

	override fun radars(request: MapRequest): Flow<AirportLocation> {
		// ...
	}
}

两者之间有一些差异@RSocketExhange@MessageMapping自 前者需要保持适合请求者和响应者的使用。例如,尽管@MessageMapping可以声明处理任意数量的路由,每条路由 成为一种模式,@RSocketExchange必须以单一的具体路线申报。有 以及与元数据相关的方法参数的细微差异,详见@MessageMappingRSocket接口以获取支持参数列表。spring-doc.cadn.net.cn

@RSocketExchange可以在类型层级用于指定所有路由的共同前缀 对于给定的RSocket服务接口。spring-doc.cadn.net.cn

@ConnectMapping

@ConnectMapping处理设置RSocket连接开头的帧,以及 任何后续的元数据推送通知通过METADATA_PUSH框架,即metadataPush(Payload)io.rsocket.RSocket.spring-doc.cadn.net.cn

@ConnectMapping方法支持与@MessageMapping相同的参数,但基于元数据和来自设置METADATA_PUSH框架。@ConnectMapping可以有一个模式,以将处理范围缩小到元数据中有路由的特定连接,或者如果没有声明模式那么所有连接都匹配。spring-doc.cadn.net.cn

@ConnectMapping方法不能返回数据,必须声明为无效单<虚空>作为返回值。如果处理返回了新的连接的错误,则该连接被拒绝。处理不能被暂停以发出请求RSocketRequester用于连接。详情请参见服务器请求者spring-doc.cadn.net.cn

元数据提取器

响应者必须解释元数据。复合元数据独立支持格式化元数据值(例如路由、安全、追踪),每个元数据值都有自己的 MIME 类型。 应用程序需要一种方式来配置支持的元数据 mime 类型,以及一种方式访问提取后的值。spring-doc.cadn.net.cn

元数据提取器是一个契约,用于获取序列化元数据并返回解码后的名称-值对,然后可以像标题一样按名称访问,例如通过@Header在注释处理方法中。spring-doc.cadn.net.cn

默认元数据提取器可以给出译码器实例用于解码元数据。出箱即用它内置支持“message/x.rsocket.routing.v0”,并将其解码为字符串并且存档时会在“路线”键下保存。对于其他哑剧类型,你需要提供 一个译码器并注册哑剧类型如下:spring-doc.cadn.net.cn

DefaultMetadataExtractor extractor = new DefaultMetadataExtractor(metadataDecoders);
extractor.metadataToExtract(fooMimeType, Foo.class, "foo");
import org.springframework.messaging.rsocket.metadataToExtract

val extractor = DefaultMetadataExtractor(metadataDecoders)
extractor.metadataToExtract<Foo>(fooMimeType, "foo")

复合元数据很好地用于组合独立的元数据值。然而,请求者可能不支持复合元数据,或者可能选择不使用复合元数据。为此,默认元数据提取器MAY需要自定义逻辑将解码值映射到输出 地图。 这里有一个使用 JSON 作为元数据的示例:spring-doc.cadn.net.cn

DefaultMetadataExtractor extractor = new DefaultMetadataExtractor(metadataDecoders);
extractor.metadataToExtract(
	MimeType.valueOf("application/vnd.myapp.metadata+json"),
	new ParameterizedTypeReference<Map<String,String>>() {},
	(jsonMap, outputMap) -> {
		outputMap.putAll(jsonMap);
	});
import org.springframework.messaging.rsocket.metadataToExtract

val extractor = DefaultMetadataExtractor(metadataDecoders)
extractor.metadataToExtract<Map<String, String>>(MimeType.valueOf("application/vnd.myapp.metadata+json")) { jsonMap, outputMap ->
	outputMap.putAll(jsonMap)
}

配置时元数据提取器通过Rocket策略,你可以让RSocketStrategies.Builder使用配置的解码器创建提取器,并只需使用回调功能自定义注册,具体如下:spring-doc.cadn.net.cn

RSocketStrategies strategies = RSocketStrategies.builder()
	.metadataExtractorRegistry(registry -> {
		registry.metadataToExtract(fooMimeType, Foo.class, "foo");
		// ...
	})
	.build();
import org.springframework.messaging.rsocket.metadataToExtract

val strategies = RSocketStrategies.builder()
		.metadataExtractorRegistry { registry: MetadataExtractorRegistry ->
			registry.metadataToExtract<Foo>(fooMimeType, "foo")
			// ...
		}
		.build()

RSocket 接口

Spring 框架允许你将 RSocket 服务定义为 Java 接口,且@RSocketExchange方法。 你可以把这样的接口传递给RSocketServiceProxyFactory创建一个代理,通过RSocketRequester执行请求。你也可以实现接口作为响应器,处理请求。spring-doc.cadn.net.cn

首先创建 的接口是@RSocketExchange方法:spring-doc.cadn.net.cn

interface RadarService {

	@RSocketExchange("radars")
	Flux<AirportLocation> getRadars(@Payload MapRequest request);

	// more RSocket exchange methods...

}

现在你可以创建一个代理,在调用方法时执行请求:spring-doc.cadn.net.cn

RSocketRequester requester = ... ;
RSocketServiceProxyFactory factory = RSocketServiceProxyFactory.builder(requester).build();

RadarService service = factory.createClient(RadarService.class);

你也可以实现该接口,作为响应者处理请求。参见注释响应者spring-doc.cadn.net.cn

方法参数

带注释的RSocket交换方法支持具有以下条件的灵活方法签名方法参数:spring-doc.cadn.net.cn

方法论证 描述

@DestinationVariablespring-doc.cadn.net.cn

添加一个路由变量来传递RSocketRequester以及从......@RSocketExchange注释以扩展路径中的模板占位符。该变量可以是字符串或任意对象,然后通过以下方式格式化toString().spring-doc.cadn.net.cn

@Payloadspring-doc.cadn.net.cn

为请求设置输入有效载荷。这可以是一个具体值,也可以是任何产生者这些值可以适配到响应式流发行人通过ReactiveAdapter注册表spring-doc.cadn.net.cn

对象,如果模仿类型spring-doc.cadn.net.cn

输入有效载荷中元数据条目的值。这可以是任意对象只要因为下一个参数是元数据条目模仿类型. 该值可以是具体的值,或任何可以适配于反应流的单一值的产生者发行人通过ReactiveAdapter注册表.spring-doc.cadn.net.cn

模仿类型spring-doc.cadn.net.cn

模仿类型对于元数据条目。前述方法参数预期为元数据值。spring-doc.cadn.net.cn

回报值

带注释的RSocket交换方法支持具体值的返回值,或任何可适配于反应流的值产生者发行人通过ReactiveAdapter注册表.spring-doc.cadn.net.cn

默认情况下,RSocket服务方法与同步(阻塞)方法的行为签名依赖于底层RSocket的响应超时设置客户运输以及 RSocket 的 keep-alive 设置。RSocketServiceProxyFactory.Builder确实暴露了blockTimeout这个选项还允许你配置响应的最长阻挡时间,但我们建议在RSocket级别设置超时值以获得更多控制。spring-doc.cadn.net.cn