diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfiguration.java index 9028ea1320..f9987d9f8b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.rsocket; import io.rsocket.transport.netty.server.TcpServerTransport; import reactor.netty.http.server.HttpServer; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -26,7 +27,9 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; +import org.springframework.messaging.rsocket.RSocketConnectorConfigurer; import org.springframework.messaging.rsocket.RSocketRequester; +import org.springframework.messaging.rsocket.RSocketRequester.Builder; import org.springframework.messaging.rsocket.RSocketStrategies; /** @@ -47,8 +50,11 @@ public class RSocketRequesterAutoConfiguration { @Bean @Scope("prototype") @ConditionalOnMissingBean - public RSocketRequester.Builder rSocketRequesterBuilder(RSocketStrategies strategies) { - return RSocketRequester.builder().rsocketStrategies(strategies); + public RSocketRequester.Builder rSocketRequesterBuilder(RSocketStrategies strategies, + ObjectProvider connectorConfigurers) { + Builder builder = RSocketRequester.builder().rsocketStrategies(strategies); + connectorConfigurers.orderedStream().forEach(builder::rsocketConnector); + return builder; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfigurationTests.java index edebbc3c00..46971f1e49 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/rsocket/RSocketRequesterAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2021 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,17 @@ package org.springframework.boot.autoconfigure.rsocket; +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.messaging.rsocket.RSocketConnectorConfigurer; import org.springframework.messaging.rsocket.RSocketRequester; +import static org.assertj.core.api.Assertions.as; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @@ -31,6 +34,7 @@ import static org.mockito.Mockito.mock; * Tests for {@link RSocketRequesterAutoConfiguration} * * @author Brian Clozel + * @author Nguyen Bao Sach */ class RSocketRequesterAutoConfigurationTests { @@ -59,6 +63,19 @@ class RSocketRequesterAutoConfigurationTests { }); } + @Test + void shouldCreateBuilderWithAvailableRSocketConnectorConfigurers() { + RSocketConnectorConfigurer first = mock(RSocketConnectorConfigurer.class); + RSocketConnectorConfigurer second = mock(RSocketConnectorConfigurer.class); + this.contextRunner.withBean("first", RSocketConnectorConfigurer.class, () -> first) + .withBean("second", RSocketConnectorConfigurer.class, () -> second).run((context) -> { + assertThat(context).getBeans(RSocketConnectorConfigurer.class).hasSize(2); + RSocketRequester.Builder builder = context.getBean(RSocketRequester.Builder.class); + assertThat(builder).extracting("rsocketConnectorConfigurers", as(InstanceOfAssertFactories.LIST)) + .containsExactly(first, second); + }); + } + @Configuration(proxyBeanMethods = false) static class CustomRSocketRequesterBuilder { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/rsocket.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/rsocket.adoc index 8318b8faf1..16ad8315e5 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/rsocket.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/features/rsocket.adoc @@ -73,7 +73,7 @@ Once the `RSocket` channel is established between server and client, any party c As a server, you can get injected with an `RSocketRequester` instance on any handler method of an RSocket `@Controller`. As a client, you need to configure and establish an RSocket connection first. -Spring Boot auto-configures an `RSocketRequester.Builder` for such cases with the expected codecs. +Spring Boot auto-configures an `RSocketRequester.Builder` for such cases with the expected codecs and apply any `RSocketConnectorConfigurer` bean. The `RSocketRequester.Builder` instance is a prototype bean, meaning each injection point will provide you with a new instance . This is done on purpose since this builder is stateful and you shouldn't create requesters with different setups using the same instance.