GH-355 Added support for deffered initialization of Function Catalog

Resolves #355
This commit is contained in:
Oleg Zhurakousky
2019-04-11 16:55:16 +02:00
parent 5256ee177c
commit cd0ca2f7dc
3 changed files with 37 additions and 13 deletions

View File

@@ -77,9 +77,12 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
protected ApplicationEventPublisher applicationEventPublisher; protected ApplicationEventPublisher applicationEventPublisher;
private AtomicBoolean initialized = new AtomicBoolean();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public <T> T lookup(Class<?> type, String name) { public <T> T lookup(Class<?> type, String name) {
initializeIfNecessary();
String functionDefinitionName = !StringUtils.hasText(name) String functionDefinitionName = !StringUtils.hasText(name)
&& this.environment.containsProperty("spring.cloud.function.definition") && this.environment.containsProperty("spring.cloud.function.definition")
? this.environment.getProperty("spring.cloud.function.definition") ? this.environment.getProperty("spring.cloud.function.definition")
@@ -90,6 +93,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
@SuppressWarnings("serial") @SuppressWarnings("serial")
@Override @Override
public Set<String> getNames(Class<?> type) { public Set<String> getNames(Class<?> type) {
initializeIfNecessary();
if (type == null) { if (type == null) {
return new HashSet<String>(getSupplierNames()) { return new HashSet<String>(getSupplierNames()) {
{ {
@@ -111,6 +115,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
* @return immutable {@link Set} of available {@link Supplier} names. * @return immutable {@link Set} of available {@link Supplier} names.
*/ */
public Set<String> getSupplierNames() { public Set<String> getSupplierNames() {
initializeIfNecessary();
return this.functions.entrySet().stream() return this.functions.entrySet().stream()
.filter(entry -> entry.getValue() instanceof Supplier) .filter(entry -> entry.getValue() instanceof Supplier)
.map(entry -> entry.getKey()) .map(entry -> entry.getKey())
@@ -122,6 +127,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
* @return immutable {@link Set} of available {@link Function} names. * @return immutable {@link Set} of available {@link Function} names.
*/ */
public Set<String> getFunctionNames() { public Set<String> getFunctionNames() {
initializeIfNecessary();
return this.functions.entrySet().stream() return this.functions.entrySet().stream()
.filter(entry -> !(entry.getValue() instanceof Supplier)) .filter(entry -> !(entry.getValue() instanceof Supplier))
.map(entry -> entry.getKey()) .map(entry -> entry.getKey())
@@ -129,10 +135,12 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
} }
public boolean hasSuppliers() { public boolean hasSuppliers() {
initializeIfNecessary();
return !CollectionUtils.isEmpty(getSupplierNames()); return !CollectionUtils.isEmpty(getSupplierNames());
} }
public boolean hasFunctions() { public boolean hasFunctions() {
initializeIfNecessary();
return !CollectionUtils.isEmpty(getFunctionNames()); return !CollectionUtils.isEmpty(getFunctionNames());
} }
@@ -144,10 +152,12 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
*/ */
@Override @Override
public int size() { public int size() {
initializeIfNecessary();
return this.functions.size(); return this.functions.size();
} }
public FunctionType getFunctionType(String name) { public FunctionType getFunctionType(String name) {
initializeIfNecessary();
return this.types.get(name); return this.types.get(name);
} }
@@ -158,6 +168,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
* @return the name of the function or null. * @return the name of the function or null.
*/ */
public String lookupFunctionName(Object function) { public String lookupFunctionName(Object function) {
initializeIfNecessary();
return this.names.containsKey(function) ? this.names.get(function) : null; return this.names.containsKey(function) ? this.names.get(function) : null;
} }
@@ -174,6 +185,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
@Override @Override
public FunctionRegistration<?> getRegistration(Object function) { public FunctionRegistration<?> getRegistration(Object function) {
initializeIfNecessary();
String functionName = function == null ? null String functionName = function == null ? null
: this.lookupFunctionName(function); : this.lookupFunctionName(function);
if (StringUtils.hasText(functionName)) { if (StringUtils.hasText(functionName)) {
@@ -189,10 +201,19 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
public <T> void register(FunctionRegistration<T> functionRegistration) { public <T> void register(FunctionRegistration<T> functionRegistration) {
Assert.notEmpty(functionRegistration.getNames(), Assert.notEmpty(functionRegistration.getNames(),
"'registration' must contain at least one name before it is registered in catalog."); "'registration' must contain at least one name before it is registered in catalog.");
initializeIfNecessary();
register(functionRegistration, functionRegistration.getNames().iterator().next()); register(functionRegistration, functionRegistration.getNames().iterator().next());
} }
private void initializeIfNecessary() {
if (initialized.compareAndSet(false, true)) {
doInitialize();
}
}
protected void doInitialize() {
}
/** /**
* Registers function wrapped by the provided FunctionRegistration with * Registers function wrapped by the provided FunctionRegistration with

View File

@@ -36,7 +36,6 @@ import com.google.gson.Gson;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -86,7 +85,7 @@ public class ContextFunctionCatalogAutoConfiguration {
protected static class BeanFactoryFunctionCatalog protected static class BeanFactoryFunctionCatalog
extends AbstractComposableFunctionRegistry extends AbstractComposableFunctionRegistry
implements SmartInitializingSingleton, BeanFactoryAware { implements BeanFactoryAware {
private ApplicationEventPublisher applicationEventPublisher; private ApplicationEventPublisher applicationEventPublisher;
@@ -96,18 +95,21 @@ public class ContextFunctionCatalogAutoConfiguration {
* Will collect all suppliers, functions, consumers and function registration as * Will collect all suppliers, functions, consumers and function registration as
* late as possible in the lifecycle. * late as possible in the lifecycle.
*/ */
@SuppressWarnings("rawtypes")
@Override @Override
public void afterSingletonsInstantiated() { protected void doInitialize() {
Map<String, Supplier> supplierBeans = this.beanFactory if (this.beanFactory != null) {
.getBeansOfType(Supplier.class); Map<String, Supplier> supplierBeans = this.beanFactory
Map<String, Function> functionBeans = this.beanFactory .getBeansOfType(Supplier.class);
.getBeansOfType(Function.class); Map<String, Function> functionBeans = this.beanFactory
Map<String, Consumer> consumerBeans = this.beanFactory .getBeansOfType(Function.class);
.getBeansOfType(Consumer.class); Map<String, Consumer> consumerBeans = this.beanFactory
Map<String, FunctionRegistration> functionRegistrationBeans = this.beanFactory .getBeansOfType(Consumer.class);
.getBeansOfType(FunctionRegistration.class); Map<String, FunctionRegistration> functionRegistrationBeans = this.beanFactory
this.doMerge(functionRegistrationBeans, consumerBeans, supplierBeans, .getBeansOfType(FunctionRegistration.class);
functionBeans); this.doMerge(functionRegistrationBeans, consumerBeans, supplierBeans,
functionBeans);
}
} }
@Override @Override

View File

@@ -297,6 +297,7 @@ public class ContextFunctionCatalogAutoConfigurationTests {
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void monoToMonoNonVoidFunction() { public void monoToMonoNonVoidFunction() {
create(MonoToMonoNonVoidConfiguration.class); create(MonoToMonoNonVoidConfiguration.class);
this.catalog.lookup("anything-doesn't-matter");
} }
@Test @Test