Alternative strategy for functional registrations
The problem with a BPP that processes FunctionRegistration is that they might not be instantiated before the FunctionRegistry. It is better to enforce the dependency order we need by injecting the registrations explicitly but lazily into the registry.
This commit is contained in:
@@ -21,6 +21,7 @@ import com.google.gson.Gson;
|
|||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanCreationException;
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
import org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||||
@@ -97,8 +98,9 @@ public class ContextFunctionCatalogInitializer
|
|||||||
|
|
||||||
performPreinitialization();
|
performPreinitialization();
|
||||||
|
|
||||||
if (context.getBeanFactory().getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class,
|
if (context.getBeanFactory().getBeanNamesForType(
|
||||||
false, false).length == 0) {
|
PropertySourcesPlaceholderConfigurer.class, false,
|
||||||
|
false).length == 0) {
|
||||||
context.registerBean(PropertySourcesPlaceholderConfigurer.class,
|
context.registerBean(PropertySourcesPlaceholderConfigurer.class,
|
||||||
() -> PropertyPlaceholderAutoConfiguration
|
() -> PropertyPlaceholderAutoConfiguration
|
||||||
.propertySourcesPlaceholderConfigurer());
|
.propertySourcesPlaceholderConfigurer());
|
||||||
@@ -110,7 +112,8 @@ public class ContextFunctionCatalogInitializer
|
|||||||
AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
|
AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
|
||||||
AutowiredAnnotationBeanPostProcessor.class);
|
AutowiredAnnotationBeanPostProcessor.class);
|
||||||
}
|
}
|
||||||
if (!context.getBeanFactory().containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) {
|
if (!context.getBeanFactory()
|
||||||
|
.containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) {
|
||||||
context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,
|
context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME,
|
||||||
ConfigurationBeanFactoryMetadata.class,
|
ConfigurationBeanFactoryMetadata.class,
|
||||||
() -> new ConfigurationBeanFactoryMetadata());
|
() -> new ConfigurationBeanFactoryMetadata());
|
||||||
@@ -124,17 +127,18 @@ public class ContextFunctionCatalogInitializer
|
|||||||
&& "gson".equals(context.getEnvironment().getProperty(
|
&& "gson".equals(context.getEnvironment().getProperty(
|
||||||
ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
|
ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY,
|
||||||
"gson"))) {
|
"gson"))) {
|
||||||
if (context.getBeanFactory().getBeanNamesForType(Gson.class, false, false).length == 0) {
|
if (context.getBeanFactory().getBeanNamesForType(Gson.class, false,
|
||||||
|
false).length == 0) {
|
||||||
context.registerBean(Gson.class, () -> new Gson());
|
context.registerBean(Gson.class, () -> new Gson());
|
||||||
}
|
}
|
||||||
context.registerBean(JsonMapper.class,
|
context.registerBean(JsonMapper.class,
|
||||||
() -> new ContextFunctionCatalogAutoConfiguration.GsonConfiguration()
|
() -> new ContextFunctionCatalogAutoConfiguration.GsonConfiguration()
|
||||||
.jsonMapper(context.getBean(Gson.class)));
|
.jsonMapper(context.getBean(Gson.class)));
|
||||||
}
|
}
|
||||||
else if (ClassUtils.isPresent(
|
else if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
|
||||||
"com.fasterxml.jackson.databind.ObjectMapper", null)) {
|
null)) {
|
||||||
if (context.getBeanFactory().getBeanNamesForType(ObjectMapper.class, false,
|
if (context.getBeanFactory().getBeanNamesForType(ObjectMapper.class,
|
||||||
false).length == 0) {
|
false, false).length == 0) {
|
||||||
context.registerBean(ObjectMapper.class, () -> new ObjectMapper());
|
context.registerBean(ObjectMapper.class, () -> new ObjectMapper());
|
||||||
}
|
}
|
||||||
context.registerBean(JsonMapper.class,
|
context.registerBean(JsonMapper.class,
|
||||||
@@ -149,7 +153,8 @@ public class ContextFunctionCatalogInitializer
|
|||||||
() -> new InMemoryFunctionCatalog());
|
() -> new InMemoryFunctionCatalog());
|
||||||
context.registerBean(FunctionRegistrationPostProcessor.class,
|
context.registerBean(FunctionRegistrationPostProcessor.class,
|
||||||
() -> new FunctionRegistrationPostProcessor(
|
() -> new FunctionRegistrationPostProcessor(
|
||||||
context.getBean(FunctionRegistry.class)));
|
context.getAutowireCapableBeanFactory()
|
||||||
|
.getBeanProvider(FunctionRegistration.class)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,33 +187,35 @@ public class ContextFunctionCatalogInitializer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class FunctionRegistrationPostProcessor implements BeanPostProcessor {
|
private class FunctionRegistrationPostProcessor implements BeanPostProcessor {
|
||||||
private final FunctionRegistry catalog;
|
@SuppressWarnings("rawtypes")
|
||||||
|
private final ObjectProvider<FunctionRegistration> functions;
|
||||||
|
|
||||||
public FunctionRegistrationPostProcessor(FunctionRegistry catalog) {
|
public FunctionRegistrationPostProcessor(
|
||||||
this.catalog = catalog;
|
@SuppressWarnings("rawtypes") ObjectProvider<FunctionRegistration> functions) {
|
||||||
|
this.functions = functions;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||||
throws BeansException {
|
throws BeansException {
|
||||||
if (bean instanceof FunctionRegistration) {
|
if (bean instanceof FunctionRegistry) {
|
||||||
FunctionRegistration<?> registration = (FunctionRegistration<?>) bean;
|
FunctionRegistry catalog = (FunctionRegistry) bean;
|
||||||
Assert.notEmpty(registration.getNames(),
|
for (FunctionRegistration<?> registration : functions) {
|
||||||
"FunctionRegistration must define at least one name. Was empty");
|
Assert.notEmpty(registration.getNames(),
|
||||||
;
|
"FunctionRegistration must define at least one name. Was empty");
|
||||||
if (registration.getType() == null) {
|
if (registration.getType() == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"You need an explicit type for the function: "
|
"You need an explicit type for the function: "
|
||||||
+ beanName);
|
+ registration.getNames());
|
||||||
// TODO: in principle Spring could know how to extract this from
|
// TODO: in principle Spring could know how to extract this
|
||||||
// the supplier, but in practice there is no functional bean
|
// from the supplier, but in practice there is no functional
|
||||||
// registration with parametric types.
|
// bean registration with parametric types.
|
||||||
|
}
|
||||||
|
catalog.register(registration);
|
||||||
}
|
}
|
||||||
catalog.register(registration);
|
|
||||||
}
|
}
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -217,7 +224,7 @@ public class ContextFunctionCatalogInitializer
|
|||||||
static class ClassUtils {
|
static class ClassUtils {
|
||||||
|
|
||||||
public static boolean isPresent(String string, ClassLoader classLoader) {
|
public static boolean isPresent(String string, ClassLoader classLoader) {
|
||||||
if (classLoader==null) {
|
if (classLoader == null) {
|
||||||
classLoader = ClassUtils.class.getClassLoader();
|
classLoader = ClassUtils.class.getClassLoader();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -232,6 +239,6 @@ public class ContextFunctionCatalogInitializer
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user