GH-944 Remove deprecations and update documentation for MessageRoutingCallback

Resolves #944
This commit is contained in:
Oleg Zhurakousky
2022-10-25 16:01:06 +02:00
parent e5302f255d
commit fd65decdb6
5 changed files with 9 additions and 67 deletions

View File

@@ -193,17 +193,6 @@ public MessageRoutingCallback customRouter() {
In the preceding example you can see a very simple implementation of `MessageRoutingCallback` which determines the function definition from In the preceding example you can see a very simple implementation of `MessageRoutingCallback` which determines the function definition from
`func_name` Message header of the incoming Message and returns the instance of `FunctionRoutingResult` containing the definition of function to invoke. `func_name` Message header of the incoming Message and returns the instance of `FunctionRoutingResult` containing the definition of function to invoke.
Additionally, the `FunctionRoutingResult` provides another constructor allowing you to provide an instance of `Message` as second argument to be used down stream.
This is primarily for runtime optimizations. To better understand this case let's look at the following scenario.
You need to route based on the payoload type. However, an input Message typically comes in as let's say JSON payload (as `byte[]`) . In order
to determine the route-to function definition you need to first process such JSON and potentially create an instance of the target type.
Once that determination is done you can pass it to `RoutingFunction` which still has a reference to the original Message with un-processed payload
This means that somewhere downstream, type conversion/transformation would need to be repeated.
Allowing you to create a new `Message` with converted payload as part of the `FunctionRoutingResult` will instruct `RoutingFunction` to use such `Message`
downstream. So effectively you letting the framework to benefit from the work you already did.
*Message Headers* *Message Headers*
If the input argument is of type `Message<?>`, you can communicate routing instruction by setting one of If the input argument is of type `Message<?>`, you can communicate routing instruction by setting one of

View File

@@ -32,17 +32,9 @@ import org.springframework.messaging.Message;
*/ */
public interface MessageRoutingCallback { public interface MessageRoutingCallback {
/**
* @deprecated in 3.1 in favor of {@link #routingResult(Message)}
*/
@Deprecated
default String functionDefinition(Message<?> message) {
return null;
}
/** /**
* Computes and returns the instance of {@link FunctionRoutingResult} which encapsulates, * Computes and returns the instance of {@link FunctionRoutingResult} which encapsulates,
* at the very minimum, function definition and optionally Message to be used downstream. * at the very minimum, function definition.
* <br><br> * <br><br>
* Providing such message is primarily an optimization feature. It could be useful for cases * Providing such message is primarily an optimization feature. It could be useful for cases
* where routing procedure is complex and results in, let's say, conversion of the payload to * where routing procedure is complex and results in, let's say, conversion of the payload to
@@ -52,39 +44,7 @@ public interface MessageRoutingCallback {
* @param message input message * @param message input message
* @return instance of {@link FunctionRoutingResult} containing the result of the routing computation * @return instance of {@link FunctionRoutingResult} containing the result of the routing computation
*/ */
default FunctionRoutingResult routingResult(Message<?> message) { default String routingResult(Message<?> message) {
return new FunctionRoutingResult(functionDefinition(message)); return (String) message.getHeaders().get(FunctionProperties.FUNCTION_DEFINITION);
}
/**
* Domain object that represents the result of the {@link MessageRoutingCallback#routingResult(Message)}
* computation. It consists of function definition and optional Message to be used downstream
* (see {@link MessageRoutingCallback#routingResult(Message)} for more details.
*
* @author Oleg Zhurakousky
*
*/
final class FunctionRoutingResult {
private final String functionDefinition;
private final Message<?> message;
FunctionRoutingResult(String functionDefinition, Message<?> message) {
this.functionDefinition = functionDefinition;
this.message = message;
}
public FunctionRoutingResult(String functionDefinition) {
this(functionDefinition, null);
}
public String getFunctionDefinition() {
return functionDefinition;
}
public Message<?> getMessage() {
return message;
}
} }
} }

View File

@@ -28,7 +28,6 @@ import reactor.core.publisher.Mono;
import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionCatalog;
import org.springframework.cloud.function.context.FunctionProperties; import org.springframework.cloud.function.context.FunctionProperties;
import org.springframework.cloud.function.context.MessageRoutingCallback; import org.springframework.cloud.function.context.MessageRoutingCallback;
import org.springframework.cloud.function.context.MessageRoutingCallback.FunctionRoutingResult;
import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper;
import org.springframework.cloud.function.context.message.MessageUtils; import org.springframework.cloud.function.context.message.MessageUtils;
import org.springframework.context.expression.MapAccessor; import org.springframework.context.expression.MapAccessor;
@@ -123,14 +122,9 @@ public class RoutingFunction implements Function<Object, Object> {
if (input instanceof Message) { if (input instanceof Message) {
Message<?> message = (Message<?>) input; Message<?> message = (Message<?>) input;
if (this.routingCallback != null) { if (this.routingCallback != null) {
FunctionRoutingResult routingResult = this.routingCallback.routingResult(message); String functionDefinition = this.routingCallback.routingResult(message);
if (routingResult != null) { if (StringUtils.hasText(functionDefinition)) {
if (StringUtils.hasText(routingResult.getFunctionDefinition())) { function = this.functionFromDefinition(functionDefinition);
function = this.functionFromDefinition(routingResult.getFunctionDefinition());
}
if (routingResult.getMessage() != null) {
message = routingResult.getMessage();
}
} }
} }
if (function == null) { if (function == null) {

View File

@@ -80,7 +80,7 @@ public class MessageRoutingCallbackTests {
return new MessageRoutingCallback() { return new MessageRoutingCallback() {
@Override @Override
public FunctionRoutingResult routingResult(Message<?> message) { public String routingResult(Message<?> message) {
String payload = new String((byte[]) message.getPayload()); String payload = new String((byte[]) message.getPayload());
MessageBuilder<?> builder; MessageBuilder<?> builder;
@@ -95,8 +95,7 @@ public class MessageRoutingCallbackTests {
} }
Message<?> m = builder.copyHeaders(message.getHeaders()).build(); Message<?> m = builder.copyHeaders(message.getHeaders()).build();
createdMessageIds.put(functionDefinition, m.getHeaders().getId()); createdMessageIds.put(functionDefinition, m.getHeaders().getId());
FunctionRoutingResult functionRoutingResult = new FunctionRoutingResult(functionDefinition, m); return functionDefinition;
return functionRoutingResult;
} }
}; };
} }

View File

@@ -109,7 +109,7 @@ public class MessageRoutingCallbackRSocketTests {
public MessageRoutingCallback customRouter() { public MessageRoutingCallback customRouter() {
return new MessageRoutingCallback() { return new MessageRoutingCallback() {
@Override @Override
public String functionDefinition(Message<?> message) { public String routingResult(Message<?> message) {
return (String) message.getHeaders().get("func_name"); return (String) message.getHeaders().get("func_name");
} }
}; };