Support for isolated class loaders extended to cover more functions
Functions with Flux and Message (as well as POJOs and Flux of POJO which were already supported) should now work if they are created in an isolated class loader. Preconditions: * The class loaders must have the reactor-core (and reactive-streams) shared between the app and the function. Practically speaking this means there has to be a parent class loader with just reactive types, and sibling children for the app and the function. This is not a new requirement (it was needed for Flux of POJO anyway). * Message types are handled reflectively, so they don't have to be in a shared class loader. But they do have to be on the class path on both sides (obviously).
This commit is contained in:
@@ -27,6 +27,7 @@ import java.util.function.Function;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||
import org.springframework.cloud.function.context.message.MessageUtils;
|
||||
import org.springframework.cloud.function.core.FunctionCatalog;
|
||||
import org.springframework.cloud.stream.annotation.Input;
|
||||
import org.springframework.cloud.stream.annotation.Output;
|
||||
@@ -91,6 +92,9 @@ public class StreamListeningFunctionInvoker implements SmartInitializingSingleto
|
||||
return flux.publish(values -> {
|
||||
Flux<?> result = function
|
||||
.apply(values.map(message -> convertInput(function).apply(message)));
|
||||
if (this.functionInspector.isMessage(function)) {
|
||||
result = result.map(message -> MessageUtils.unpack(function, message));
|
||||
}
|
||||
Flux<Map<String, Object>> aggregate = headers(values);
|
||||
return result.withLatestFrom(aggregate, (p, m) -> message(p, m));
|
||||
});
|
||||
@@ -141,7 +145,7 @@ public class StreamListeningFunctionInvoker implements SmartInitializingSingleto
|
||||
.get(StreamConfigurationProperties.ROUTE_KEY);
|
||||
name = stash(key);
|
||||
}
|
||||
if (name==null && defaultRoute != null) {
|
||||
if (name == null && defaultRoute != null) {
|
||||
name = stash(defaultRoute);
|
||||
}
|
||||
if (name == null) {
|
||||
@@ -155,10 +159,10 @@ public class StreamListeningFunctionInvoker implements SmartInitializingSingleto
|
||||
else {
|
||||
for (String candidate : names) {
|
||||
Object function = functionCatalog.lookupFunction(candidate);
|
||||
if (function==null) {
|
||||
if (function == null) {
|
||||
function = functionCatalog.lookupConsumer(candidate);
|
||||
}
|
||||
if (function==null) {
|
||||
if (function == null) {
|
||||
continue;
|
||||
}
|
||||
Class<?> inputType = functionInspector.getInputType(function);
|
||||
@@ -202,8 +206,8 @@ public class StreamListeningFunctionInvoker implements SmartInitializingSingleto
|
||||
Class<?> inputType = functionInspector.getInputType(function);
|
||||
return m -> {
|
||||
if (functionInspector.isMessage(function)) {
|
||||
return MessageBuilder.withPayload(convertPayload(inputType, m))
|
||||
.copyHeaders(m.getHeaders()).build();
|
||||
return MessageUtils.create(function, convertPayload(inputType, m),
|
||||
m.getHeaders());
|
||||
}
|
||||
else {
|
||||
return convertPayload(inputType, m);
|
||||
|
||||
@@ -22,6 +22,7 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.cloud.function.context.message.MessageUtils;
|
||||
import org.springframework.cloud.function.core.FunctionCatalog;
|
||||
import org.springframework.cloud.stream.messaging.Source;
|
||||
import org.springframework.integration.endpoint.MessageProducerSupport;
|
||||
@@ -86,7 +87,8 @@ public class SupplierInvokingMessageProducer<T> extends MessageProducerSupport {
|
||||
if (supplier != null) {
|
||||
suppliers.add(name);
|
||||
disposables.put(name,
|
||||
supplier.get().subscribeOn(Schedulers.elastic()).subscribe(m -> send(name, m)));
|
||||
supplier.get().subscribeOn(Schedulers.elastic())
|
||||
.subscribe(m -> send(name, m)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,16 +96,10 @@ public class SupplierInvokingMessageProducer<T> extends MessageProducerSupport {
|
||||
}
|
||||
|
||||
private void send(String name, Object payload) {
|
||||
Message<?> message;
|
||||
if (payload instanceof Message) {
|
||||
message = MessageBuilder.fromMessage((Message<?>) payload)
|
||||
.setHeaderIfAbsent(StreamConfigurationProperties.ROUTE_KEY, name)
|
||||
.build();
|
||||
}
|
||||
else {
|
||||
message = MessageBuilder.withPayload(payload)
|
||||
.setHeader(StreamConfigurationProperties.ROUTE_KEY, name).build();
|
||||
}
|
||||
Supplier<Flux<?>> supplier = functionCatalog.lookupSupplier(name);
|
||||
Message<?> message = MessageUtils.unpack(supplier, payload);
|
||||
message = MessageBuilder.fromMessage(message)
|
||||
.setHeaderIfAbsent(StreamConfigurationProperties.ROUTE_KEY, name).build();
|
||||
getOutputChannel().send(message);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user