From 71ee26b0a1264329fb8a63c4b9df38c9bc0c041f Mon Sep 17 00:00:00 2001 From: Chris Bono Date: Wed, 17 Aug 2022 00:07:29 -0500 Subject: [PATCH] Use empty context for AOT binder child context Previously, when running in AOT mode the binder child context was created w/ the same beans as when in JVM mode. The whole point of the former is to static initialize an empty fresh context using the AOT generated initializer. --- .../binder/BinderChildContextInitializer.java | 2 +- .../stream/binder/DefaultBinderFactory.java | 47 +++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java index 93c89d9f1..29a9ba46a 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/BinderChildContextInitializer.java @@ -153,7 +153,7 @@ public class BinderChildContextInitializer implements ApplicationContextAware, B this.logger.debug(() -> "Generating AOT child context initializer for " + name); GenerationContext childGenerationContext = generationContext.withName(name + "Binder"); ClassName initializerClassName = aotGenerator.processAheadOfTime(context, childGenerationContext); - method.addStatement("$T" + name + "Initializer = new $L()", ApplicationContextInitializer.class, + method.addStatement("$T " + name + "Initializer = new $L()", ApplicationContextInitializer.class, ConfigurableApplicationContext.class, initializerClassName); method.addStatement("initializers.put($S," + name + "Initializer)", name); }); diff --git a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java index 0c7a20336..f18d11d89 100644 --- a/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java +++ b/core/spring-cloud-stream/src/main/java/org/springframework/cloud/stream/binder/DefaultBinderFactory.java @@ -265,9 +265,7 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl ConfigurableApplicationContext binderProducingContext; if (this.binderChildContextInitializers.containsKey(configurationName)) { this.logger.info("Using AOT pre-prepared initializer to construct binder child context for " + configurationName); - binderProducingContext = this.initializeBinderContextSimple(configurationName, binderProperties, - binderType, binderConfiguration, false); - GenericApplicationContext c = null; + binderProducingContext = this.createUnitializedContextForAOT(configurationName, binderProperties, binderConfiguration); this.binderChildContextInitializers.get(configurationName).initialize(binderProducingContext); binderProducingContext.refresh(); } @@ -447,6 +445,49 @@ public class DefaultBinderFactory implements BinderFactory, DisposableBean, Appl return binderProducingContext; } + /** + * Creates a bare minimum application context that can be initialized by AOT. + * + * @param configurationName binder configuration name + * @param binderProperties binder properties + * @param binderConfiguration binder configuration + * @return a binder child application context suitable for AOT initialization + */ + GenericApplicationContext createUnitializedContextForAOT(String configurationName, + Map binderProperties, BinderConfiguration binderConfiguration) { + + GenericApplicationContext binderContext = new GenericApplicationContext(); + + MapPropertySource binderPropertySource = new MapPropertySource(configurationName, binderProperties); + binderContext.getEnvironment().getPropertySources().addFirst(binderPropertySource); + binderContext.setDisplayName(configurationName + "_context"); + boolean useApplicationContextAsParent = binderProperties.isEmpty() && this.context != null; + ConfigurableEnvironment environment = this.context != null ? this.context.getEnvironment() : null; + if (useApplicationContextAsParent) { + binderContext.setParent(this.context); + } + else if (this.context != null) { + binderContext.addApplicationListener(event -> { + if (context != null) { + try { + context.publishEvent(event); + } + catch (Exception e) { + logger.warn("Failed to publish " + event, e); + } + } + }); + if (environment != null && (useApplicationContextAsParent || binderConfiguration.isInheritEnvironment())) { + binderContext.getEnvironment().merge(environment); + binderContext.getEnvironment().getPropertySources().remove("configurationProperties"); + binderContext.getEnvironment().getPropertySources() + .addFirst(new MapPropertySource("defaultBinderFactoryProperties", + Collections.singletonMap("spring.main.web-application-type", "NONE"))); + } + } + return binderContext; + } + /** * Ensures that nested properties are flattened (i.e., foo.bar=baz instead of * foo={bar=baz}).