Simplify RSocket client responder config

Now that responder RSocketStrategies also exposes responder strategies,
AnnotationClientResponderConfigurer is reduced and no longer needs to
be public. This commit folds it into RSocketMessageHandler as a nested
class and exposes it as a ClientRSocketFactoryConfigurer through a
static method that accepts the handlers to use.

Effectively a shortcut for creating RSocketMessageHandler, giving it
RSocketStrategies, calling afterPropertiesSet, and then the instance
createResponder.

See gh-23314
This commit is contained in:
Rossen Stoyanchev
2019-07-24 11:13:44 +01:00
parent c456950bc3
commit e19e36ae4c
4 changed files with 50 additions and 108 deletions

View File

@@ -30,7 +30,7 @@ import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.codec.Decoder;
import org.springframework.lang.Nullable;
import org.springframework.messaging.rsocket.annotation.support.AnnotationClientResponderConfigurer;
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
import org.springframework.util.MimeType;
/**
@@ -165,14 +165,15 @@ public interface RSocketRequester {
/**
* Callback to configure the {@code ClientRSocketFactory} directly.
* <p>See {@link AnnotationClientResponderConfigurer} for configuring a
* client side responder.
* <p>See static factory method
* {@link RSocketMessageHandler#clientResponder(Object...)} for
* configuring a client side responder with annotated methods.
* <p><strong>Note:</strong> Do not set {@link #dataMimeType(MimeType)}
* and {@link #metadataMimeType(MimeType)} directly on the
* {@code ClientRSocketFactory}. Use the shortcuts on this builder
* instead since the created {@code RSocketRequester} needs to be aware
* of those settings.
* @see AnnotationClientResponderConfigurer
* @see RSocketMessageHandler#clientResponder(Object...)
*/
RSocketRequester.Builder rsocketFactory(ClientRSocketFactoryConfigurer configurer);

View File

@@ -1,101 +0,0 @@
/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.messaging.rsocket.annotation.support;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import io.rsocket.RSocketFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.lang.Nullable;
import org.springframework.messaging.rsocket.ClientRSocketFactoryConfigurer;
import org.springframework.messaging.rsocket.RSocketStrategies;
import org.springframework.util.Assert;
/**
* {@link ClientRSocketFactoryConfigurer} to configure and plug in a responder
* that handles requests via annotated handler methods. Effectively a thin layer over
* {@link RSocketMessageHandler} that provides a programmatic way to configure
* it and obtain a responder via {@link RSocketMessageHandler#clientResponder()
* clientResponder()}.
*
* @author Rossen Stoyanchev
* @since 5.2
*/
public final class AnnotationClientResponderConfigurer implements ClientRSocketFactoryConfigurer {
private final List<Object> handlers = new ArrayList<>();
@Nullable
private RSocketStrategies strategies;
private AnnotationClientResponderConfigurer(List<Object> handlers) {
for (Object obj : handlers) {
this.handlers.add(obj instanceof Class ? BeanUtils.instantiateClass((Class<?>) obj) : obj);
}
}
/**
* Configure handlers to detect {@code @MessasgeMapping} handler methods on.
* This is used to set {@link RSocketMessageHandler#setHandlers(List)}.
*/
public AnnotationClientResponderConfigurer handlers(Object... handlers) {
this.handlers.addAll(Arrays.asList(handlers));
return this;
}
// Implementation of ClientRSocketFactoryConfigurer
@Override
public void configureWithStrategies(RSocketStrategies strategies) {
this.strategies = strategies;
}
@Override
public void configure(RSocketFactory.ClientRSocketFactory factory) {
Assert.notEmpty(this.handlers, "No handlers");
RSocketMessageHandler messageHandler = new RSocketMessageHandler();
messageHandler.setHandlers(this.handlers);
messageHandler.setRSocketStrategies(this.strategies);
messageHandler.afterPropertiesSet();
factory.acceptor(messageHandler.clientResponder());
}
// Static factory methods
/**
* Create an {@code AnnotationClientResponderConfigurer} with the given handlers
* to check for {@code @MessasgeMapping} handler methods.
*/
public static AnnotationClientResponderConfigurer withHandlers(Object... handlers) {
return new AnnotationClientResponderConfigurer(Arrays.asList(handlers));
}
/**
* Create an {@code AnnotationClientResponderConfigurer} to set up further.
*/
public static AnnotationClientResponderConfigurer create() {
return new AnnotationClientResponderConfigurer(Collections.emptyList());
}
}

View File

@@ -24,10 +24,12 @@ import java.util.function.Function;
import io.rsocket.ConnectionSetupPayload;
import io.rsocket.RSocket;
import io.rsocket.RSocketFactory;
import io.rsocket.SocketAcceptor;
import io.rsocket.frame.FrameType;
import reactor.core.publisher.Mono;
import org.springframework.beans.BeanUtils;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.codec.Decoder;
@@ -40,6 +42,7 @@ import org.springframework.messaging.handler.DestinationPatternsMessageCondition
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.reactive.MessageMappingMessageHandler;
import org.springframework.messaging.handler.invocation.reactive.HandlerMethodReturnValueHandler;
import org.springframework.messaging.rsocket.ClientRSocketFactoryConfigurer;
import org.springframework.messaging.rsocket.DefaultMetadataExtractor;
import org.springframework.messaging.rsocket.MetadataExtractor;
import org.springframework.messaging.rsocket.RSocketRequester;
@@ -324,10 +327,50 @@ public class RSocketMessageHandler extends MessageMappingMessageHandler {
Assert.notNull(strategies, "No RSocketStrategies. Was afterPropertiesSet not called?");
RSocketRequester requester = RSocketRequester.wrap(rsocket, dataMimeType, metadataMimeType, strategies);
Assert.notNull(this.metadataExtractor, () -> "No MetadataExtractor. Was afterPropertiesSet not called?");
Assert.state(this.metadataExtractor != null,
() -> "No MetadataExtractor. Was afterPropertiesSet not called?");
Assert.state(getRouteMatcher() != null,
() -> "No RouteMatcher. Was afterPropertiesSet not called?");
return new MessagingRSocket(dataMimeType, metadataMimeType, this.metadataExtractor, requester,
this, getRouteMatcher(), strategies);
}
public static ClientRSocketFactoryConfigurer clientResponder(Object... handlers) {
return new ResponderConfigurer(handlers);
}
private static final class ResponderConfigurer implements ClientRSocketFactoryConfigurer {
private final List<Object> handlers = new ArrayList<>();
@Nullable
private RSocketStrategies strategies;
private ResponderConfigurer(Object... handlers) {
Assert.notEmpty(handlers, "No handlers");
for (Object obj : handlers) {
this.handlers.add(obj instanceof Class ? BeanUtils.instantiateClass((Class<?>) obj) : obj);
}
}
@Override
public void configureWithStrategies(RSocketStrategies strategies) {
this.strategies = strategies;
}
@Override
public void configure(RSocketFactory.ClientRSocketFactory factory) {
RSocketMessageHandler handler = new RSocketMessageHandler();
handler.setHandlers(this.handlers);
handler.setRSocketStrategies(this.strategies);
handler.afterPropertiesSet();
factory.acceptor(handler.clientResponder());
}
}
}

View File

@@ -39,7 +39,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.rsocket.annotation.ConnectMapping;
import org.springframework.messaging.rsocket.annotation.support.AnnotationClientResponderConfigurer;
import org.springframework.messaging.rsocket.annotation.support.RSocketMessageHandler;
import org.springframework.stereotype.Controller;
@@ -111,7 +110,7 @@ public class RSocketServerToClientIntegrationTests {
factory.metadataMimeType("text/plain");
factory.setupPayload(ByteBufPayload.create("", connectionRoute));
})
.rsocketFactory(AnnotationClientResponderConfigurer.withHandlers(new ClientHandler()))
.rsocketFactory(RSocketMessageHandler.clientResponder(new ClientHandler()))
.rsocketStrategies(context.getBean(RSocketStrategies.class))
.connectTcp("localhost", server.address().getPort())
.block();