From 150f1401968811529fb45d2261b778228e8a5437 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Thu, 7 Oct 2021 15:02:06 +0200 Subject: [PATCH] GH-752 Add support to stop caching functions in FunctionCatalog Resolves #752 --- .../catalog/SimpleFunctionRegistry.java | 26 +++++++++++---- .../catalog/SimpleFunctionRegistryTests.java | 33 +++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java index 21ef6fc50..6f49f12da 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistry.java @@ -194,7 +194,6 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect @SuppressWarnings("unchecked") T doLookup(Class type, String functionDefinition, String[] expectedOutputMimeTypes) { FunctionInvocationWrapper function = this.wrappedFunctionDefinitions.get(functionDefinition); - if (function == null) { function = this.compose(type, functionDefinition); } @@ -269,10 +268,18 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect .filter(fr -> fr.getNames().contains(functionName)) .findFirst() .orElseGet(() -> null); - return functionRegistration != null + FunctionInvocationWrapper function = functionRegistration != null ? this.invocationWrapperInstance(functionName, functionRegistration.getTarget(), functionRegistration.getType().getType()) : null; - + if (functionRegistration != null && functionRegistration.getProperties().containsKey("singleton")) { + try { + function.isSingleton = Boolean.parseBoolean(functionRegistration.getProperties().get("singleton")); + } + catch (Exception e) { + // ignore + } + } + return function; } /* @@ -297,7 +304,9 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect composedFunction = (FunctionInvocationWrapper) composedFunction.andThen((Function) andThenFunction); } composedFunction = this.enrichInputIfNecessary(composedFunction); - this.wrappedFunctionDefinitions.put(composedFunction.functionDefinition, composedFunction); + if (composedFunction.isSingleton) { + this.wrappedFunctionDefinitions.put(composedFunction.functionDefinition, composedFunction); + } } } if (logger.isDebugEnabled()) { @@ -370,6 +379,8 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect private boolean skipOutputConversion; + private boolean isSingleton = true; + /* * This is primarily to support Stream's ability to access * un-converted payload (e.g., to evaluate expression on some attribute of a payload) @@ -389,9 +400,6 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect } FunctionInvocationWrapper(String functionDefinition, Object target, Type inputType, Type outputType) { -// if (functionAroundWrapper != null) { -// this.setSkipOutputConversion(true); -// } this.target = target; this.inputType = this.normalizeType(inputType); this.outputType = this.normalizeType(outputType); @@ -399,6 +407,10 @@ public class SimpleFunctionRegistry implements FunctionRegistry, FunctionInspect this.message = this.inputType != null && FunctionTypeUtils.isMessage(this.inputType); } + public boolean isPrototype() { + return this.isPrototype(); + } + public void setSkipInputConversion(boolean skipInputConversion) { if (logger.isDebugEnabled() && skipInputConversion) { logger.debug("'skipInputConversion' was explicitely set to true. No input conversion will be attempted"); diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java index 4dc8451d6..0bcf484ab 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/SimpleFunctionRegistryTests.java @@ -86,6 +86,39 @@ public class SimpleFunctionRegistryTests { this.conversionService = new DefaultConversionService(); } + @Test + public void testCachingOfFunction() { + Echo function = new Echo(); + FunctionRegistration registration = new FunctionRegistration<>( + function, "echo").type(FunctionType.of(Echo.class)); + SimpleFunctionRegistry catalog = new SimpleFunctionRegistry(this.conversionService, this.messageConverter, + new JacksonMapper(new ObjectMapper())); + catalog.register(registration); + + FunctionInvocationWrapper instanceA = catalog.lookup("echo", "application/json"); + FunctionInvocationWrapper instanceb = catalog.lookup("echo", "text/plain"); + FunctionInvocationWrapper instanceC = catalog.lookup("echo", "foo/bar"); + + assertThat(instanceA).isSameAs(instanceb).isSameAs(instanceC); + } + + @Test + public void testNoCachingOfFunction() { + Echo function = new Echo(); + FunctionRegistration registration = new FunctionRegistration<>( + function, "echo").type(FunctionType.of(Echo.class)); + registration.getProperties().put("singleton", "false"); + SimpleFunctionRegistry catalog = new SimpleFunctionRegistry(this.conversionService, this.messageConverter, + new JacksonMapper(new ObjectMapper())); + catalog.register(registration); + + FunctionInvocationWrapper instanceA = catalog.lookup("echo", "application/json"); + FunctionInvocationWrapper instanceb = catalog.lookup("echo", "text/plain"); + FunctionInvocationWrapper instanceC = catalog.lookup("echo", "foo/bar"); + + assertThat(instanceA).isNotSameAs(instanceb).isNotSameAs(instanceC); + } + @Test public void testSCF640() { Echo function = new Echo();