From bb1c97251fcd8999ad0562f8e9664e9c036e6080 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Tue, 2 Oct 2018 12:06:37 +0100 Subject: [PATCH] Use ApplicationContextInitializer if provided An Initializer is more efficient than using @Configuration. --- .../azure/AzureSpringFunctionInitializer.java | 33 +++++++++-- .../ContextFunctionCatalogInitializer.java | 55 +++++++++++++------ 2 files changed, 65 insertions(+), 23 deletions(-) diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java index c54fc9b8a..0a902b956 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java @@ -32,12 +32,15 @@ import com.microsoft.azure.functions.ExecutionContext; import org.reactivestreams.Publisher; +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.catalog.FunctionInspector; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.ClassUtils; @@ -92,12 +95,9 @@ public class AzureSpringFunctionInitializer implements Closeable { if (context == null) { synchronized (AzureSpringFunctionInitializer.class) { if (context == null) { - SpringApplicationBuilder builder = new SpringApplicationBuilder( - configurationClass); ClassUtils.overrideThreadContextClassLoader( AzureSpringFunctionInitializer.class.getClassLoader()); - - context = builder.web(WebApplicationType.NONE).run(); + springApplication().run(); AzureSpringFunctionInitializer.context = context; } } @@ -134,6 +134,29 @@ public class AzureSpringFunctionInitializer implements Closeable { } } + private SpringApplication springApplication() { + ApplicationContextInitializer initializer = null; + Class sourceClass = configurationClass; + if (ApplicationContextInitializer.class.isAssignableFrom(sourceClass)) { + initializer = BeanUtils.instantiateClass(configurationClass, ApplicationContextInitializer.class); + sourceClass = Object.class; + } + SpringApplication application; + if (initializer!=null) { + application = new SpringApplication(sourceClass) { + @Override + protected void load(ApplicationContext context, Object[] sources) { + } + }; + application.addInitializers(initializer); + application.setDefaultProperties(Collections.singletonMap("spring.functional.enabled", "true")); + } else { + application = new SpringApplication(sourceClass); + } + application.setWebApplicationType(WebApplicationType.NONE); + return application; + } + protected boolean isSingleInput(Function function, Object input) { if (!(input instanceof Collection)) { return true; diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java index 122bc0635..4f0442546 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java @@ -26,9 +26,11 @@ import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.boot.autoconfigure.BackgroundPreinitializer; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata; import org.springframework.boot.context.properties.ConfigurationPropertiesBindingPostProcessor; +import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionRegistry; import org.springframework.cloud.function.context.catalog.InMemoryFunctionCatalog; @@ -95,19 +97,28 @@ public class ContextFunctionCatalogInitializer performPreinitialization(); - context.registerBean(PropertySourcesPlaceholderConfigurer.class, - () -> PropertyPlaceholderAutoConfiguration - .propertySourcesPlaceholderConfigurer()); + if (context.getBeanNamesForType(PropertySourcesPlaceholderConfigurer.class, + false, false).length == 0) { + context.registerBean(PropertySourcesPlaceholderConfigurer.class, + () -> PropertyPlaceholderAutoConfiguration + .propertySourcesPlaceholderConfigurer()); + } - context.registerBean( - AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, - AutowiredAnnotationBeanPostProcessor.class); - context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, - ConfigurationBeanFactoryMetadata.class, - () -> new ConfigurationBeanFactoryMetadata()); - context.registerBean(ConfigurationPropertiesBindingPostProcessor.BEAN_NAME, - ConfigurationPropertiesBindingPostProcessor.class, - () -> new ConfigurationPropertiesBindingPostProcessor()); + if (!context.containsBean( + AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) { + context.registerBean( + AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, + AutowiredAnnotationBeanPostProcessor.class); + } + if (!context.containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) { + context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, + ConfigurationBeanFactoryMetadata.class, + () -> new ConfigurationBeanFactoryMetadata()); + context.registerBean( + ConfigurationPropertiesBindingPostProcessor.BEAN_NAME, + ConfigurationPropertiesBindingPostProcessor.class, + () -> new ConfigurationPropertiesBindingPostProcessor()); + } if (ClassUtils.isPresent("com.google.gson.Gson", null) && !"gson".equals(context.getEnvironment().getProperty( @@ -132,14 +143,20 @@ public class ContextFunctionCatalogInitializer } - context.registerBean(InMemoryFunctionCatalog.class, - () -> new InMemoryFunctionCatalog()); - context.registerBean(FunctionRegistrationPostProcessor.class, - () -> new FunctionRegistrationPostProcessor( - context.getBean(FunctionRegistry.class))); + if (context.getBeanNamesForType(FunctionCatalog.class, false, + false).length == 0) { + context.registerBean(InMemoryFunctionCatalog.class, + () -> new InMemoryFunctionCatalog()); + context.registerBean(FunctionRegistrationPostProcessor.class, + () -> new FunctionRegistrationPostProcessor( + context.getBean(FunctionRegistry.class))); + } } private void performPreinitialization() { + if (Boolean.getBoolean(BackgroundPreinitializer.IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME)) { + return; + } try { Thread thread = new Thread(new Runnable() { @@ -176,7 +193,9 @@ public class ContextFunctionCatalogInitializer throws BeansException { if (bean instanceof FunctionRegistration) { FunctionRegistration registration = (FunctionRegistration) bean; - Assert.notEmpty(registration.getNames(), "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) { throw new IllegalStateException( "You need an explicit type for the function: "