Refactor RSocket handler selection

1. Consolidate config options for handler detection in the base class
AbstractMethodMessageHandler with sub-classes like RSocketMessageHandler
now only setting the handler predicate by default (e.g. @Controller).

2. Remove autoDetection flag in favor of just having the mutually
exclusive handler Predicate<Object> vs manually registered List<Object>.
Or if both are desired for some reason, then manually register first,
and set the predicate second.
This commit is contained in:
Rossen Stoyanchev 2019-06-20 12:09:51 +01:00
parent 7d68a65dc0
commit 772087fe18
3 changed files with 52 additions and 77 deletions

View File

@ -83,10 +83,6 @@ import org.springframework.validation.Validator;
public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<CompositeMessageCondition>
implements EmbeddedValueResolverAware {
@Nullable
private Predicate<Class<?>> handlerPredicate =
beanType -> AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
private final List<Decoder<?>> decoders = new ArrayList<>();
@Nullable
@ -104,59 +100,10 @@ public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<C
AntPathMatcher pathMatcher = new AntPathMatcher();
pathMatcher.setPathSeparator(".");
this.routeMatcher = new SimpleRouteMatcher(pathMatcher);
setHandlerPredicate(type -> AnnotatedElementUtils.hasAnnotation(type, Controller.class));
}
/**
* Manually configure handlers to check for {@code @MessageMapping} methods.
* <p><strong>Note:</strong> the given handlers are not required to be
* annotated with {@code @Controller}. Consider also using
* {@link #setAutoDetectDisabled()} if the intent is to use these handlers
* instead of, and not in addition to {@code @Controller} classes. Or
* alternatively use {@link #setHandlerPredicate(Predicate)} to select a
* different set of beans based on a different criteria.
* @param handlers the handlers to register
* @see #setAutoDetectDisabled()
* @see #setHandlerPredicate(Predicate)
*/
public void setHandlers(List<Object> handlers) {
for (Object handler : handlers) {
detectHandlerMethods(handler);
}
// Disable auto-detection..
this.handlerPredicate = null;
}
/**
* Configure the predicate to use for selecting which Spring beans to check
* for {@code @MessageMapping} methods. When set to {@code null},
* auto-detection is turned off which is what
* {@link #setAutoDetectDisabled()} does internally.
* <p>The predicate used by default selects {@code @Controller} classes.
* @see #setHandlers(List)
* @see #setAutoDetectDisabled()
*/
public void setHandlerPredicate(@Nullable Predicate<Class<?>> handlerPredicate) {
this.handlerPredicate = handlerPredicate;
}
/**
* Return the {@link #setHandlerPredicate configured} handler predicate.
*/
@Nullable
public Predicate<Class<?>> getHandlerPredicate() {
return this.handlerPredicate;
}
/**
* Disable auto-detection of {@code @MessageMapping} methods, e.g. in
* {@code @Controller}s, by setting {@link #setHandlerPredicate(Predicate)
* setHandlerPredicate(null)}.
*/
public void setAutoDetectDisabled() {
this.handlerPredicate = null;
}
/**
* Configure the decoders to use for incoming payloads.
*/
@ -264,11 +211,6 @@ public class MessageMappingMessageHandler extends AbstractMethodMessageHandler<C
return Collections.emptyList();
}
@Override
protected Predicate<Class<?>> initHandlerPredicate() {
return this.handlerPredicate;
}
@Override
protected CompositeMessageCondition getMappingForMethod(Method method, Class<?> handlerType) {

View File

@ -86,6 +86,12 @@ public abstract class AbstractMethodMessageHandler<T>
protected final Log logger = LogFactory.getLog(getClass());
@Nullable
private Predicate<Class<?>> handlerPredicate;
@Nullable
List<Object> handlers;
private ArgumentResolverConfigurer argumentResolverConfigurer = new ArgumentResolverConfigurer();
private ReturnValueHandlerConfigurer returnValueHandlerConfigurer = new ReturnValueHandlerConfigurer();
@ -103,6 +109,38 @@ public abstract class AbstractMethodMessageHandler<T>
private final MultiValueMap<String, T> destinationLookup = new LinkedMultiValueMap<>(64);
/**
* Configure a predicate for selecting which Spring beans to check for the
* presence of message handler methods.
* <p>This is not set by default. However sub-classes may initialize it to
* some default strategy (e.g. {@code @Controller} classes).
* @see #setHandlers(List)
*/
public void setHandlerPredicate(@Nullable Predicate<Class<?>> handlerPredicate) {
this.handlerPredicate = handlerPredicate;
}
/**
* Return the {@link #setHandlerPredicate configured} handler predicate.
*/
@Nullable
public Predicate<Class<?>> getHandlerPredicate() {
return this.handlerPredicate;
}
/**
* Manually configure the handlers to check for the presence of message
* handling methods, which also disables auto-detection via a
* {@link #setHandlerPredicate(Predicate) handlerPredicate}. If you do not
* want to disable auto-detection, then call this method first, and then set
* the handler predicate.
* @param handlers the handlers to check
*/
public void setHandlers(List<Object> handlers) {
this.handlers = handlers;
this.handlerPredicate = null;
}
/**
* Configure custom resolvers for handler method arguments.
*/
@ -233,9 +271,14 @@ public abstract class AbstractMethodMessageHandler<T>
logger.warn("No ApplicationContext available for detecting beans with message handling methods.");
return;
}
Predicate<Class<?>> handlerPredicate = initHandlerPredicate();
if (handlerPredicate == null) {
logger.warn("[" + getBeanName() + "] No auto-detection of handler methods (e.g. in @Controller).");
if (this.handlers != null) {
for (Object handler : this.handlers) {
detectHandlerMethods(handler);
}
}
Predicate<Class<?>> predicate = this.handlerPredicate;
if (predicate == null) {
logger.warn("[" + getBeanName() + "] Auto-detection of message handling methods is off.");
return;
}
for (String beanName : this.applicationContext.getBeanNamesForType(Object.class)) {
@ -250,21 +293,13 @@ public abstract class AbstractMethodMessageHandler<T>
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
}
}
if (beanType != null && handlerPredicate.test(beanType)) {
if (beanType != null && predicate.test(beanType)) {
detectHandlerMethods(beanName);
}
}
}
}
/**
* Return the predicate to use to check whether a given Spring bean should
* be introspected for message handling methods. If {@code null} is
* returned, auto-detection is effectively disabled.
*/
@Nullable
protected abstract Predicate<Class<?>> initHandlerPredicate();
/**
* Detect if the given handler has any methods that can handle messages and if
* so register it with the extracted mapping information.

View File

@ -24,7 +24,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.junit.Test;
import org.reactivestreams.Publisher;
@ -203,6 +202,10 @@ public class MethodMessageHandlerTests {
private PathMatcher pathMatcher = new AntPathMatcher();
public TestMethodMessageHandler() {
setHandlerPredicate(handlerType -> handlerType.getName().endsWith("Controller"));
}
@Override
protected List<? extends HandlerMethodArgumentResolver> initArgumentResolvers() {
return Collections.emptyList();
@ -213,11 +216,6 @@ public class MethodMessageHandlerTests {
return Collections.singletonList(this.returnValueHandler);
}
@Override
protected Predicate<Class<?>> initHandlerPredicate() {
return handlerType -> handlerType.getName().endsWith("Controller");
}
@Nullable
public Object getLastReturnValue() {
return this.returnValueHandler.getLastReturnValue();