Skip to content

Commit 5b126b0

Browse files
committed
Replace binder as contributors are processed
Update `ConfigDataEnvironment` so that the bootstrap `Binder` is replaced as contributors are processed. The final `Binder` is now also added without the `FAIL_ON_BIND_TO_INACTIVE_SOURCE` option so that properties can be bound at the last stage even if values exist in an inactive profile-specific document. Closes gh-24669
1 parent ac4243d commit 5b126b0

File tree

4 files changed

+33
-14
lines changed

4 files changed

+33
-14
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/config/ConfigDataEnvironment.java

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import java.util.LinkedHashSet;
2323
import java.util.List;
2424
import java.util.Set;
25-
import java.util.function.Supplier;
2625

2726
import org.apache.commons.logging.Log;
2827

@@ -107,6 +106,10 @@ class ConfigDataEnvironment {
107106

108107
private static final Bindable<List<String>> STRING_LIST = Bindable.listOf(String.class);
109108

109+
private static final BinderOption[] ALLOW_INACTIVE_BINDING = {};
110+
111+
private static final BinderOption[] DENY_INACTIVE_BINDING = { BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE };
112+
110113
private final DeferredLogFactory logFactory;
111114

112115
private final Log logger;
@@ -222,25 +225,22 @@ private ConfigDataEnvironmentContributor createInitialImportContributor(ConfigDa
222225
void processAndApply() {
223226
ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers,
224227
this.loaders);
225-
registerBootstrapBinder(() -> this.contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
228+
registerBootstrapBinder(this.contributors, null, DENY_INACTIVE_BINDING);
226229
ConfigDataEnvironmentContributors contributors = processInitial(this.contributors, importer);
227-
Binder initialBinder = contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE);
228-
registerBootstrapBinder(() -> initialBinder);
229-
ConfigDataActivationContext activationContext = createActivationContext(initialBinder);
230+
ConfigDataActivationContext activationContext = createActivationContext(
231+
contributors.getBinder(null, BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE));
230232
contributors = processWithoutProfiles(contributors, importer, activationContext);
231233
activationContext = withProfiles(contributors, activationContext);
232234
contributors = processWithProfiles(contributors, importer, activationContext);
233235
applyToEnvironment(contributors, activationContext);
234236
}
235237

236-
private void registerBootstrapBinder(Supplier<Binder> supplier) {
237-
this.bootstrapContext.register(Binder.class, InstanceSupplier.from(supplier).withScope(Scope.PROTOTYPE));
238-
}
239-
240238
private ConfigDataEnvironmentContributors processInitial(ConfigDataEnvironmentContributors contributors,
241239
ConfigDataImporter importer) {
242240
this.logger.trace("Processing initial config data environment contributors without activation context");
243-
return contributors.withProcessedImports(importer, null);
241+
contributors = contributors.withProcessedImports(importer, null);
242+
registerBootstrapBinder(contributors, null, DENY_INACTIVE_BINDING);
243+
return contributors;
244244
}
245245

246246
private ConfigDataActivationContext createActivationContext(Binder initialBinder) {
@@ -259,7 +259,9 @@ private ConfigDataActivationContext createActivationContext(Binder initialBinder
259259
private ConfigDataEnvironmentContributors processWithoutProfiles(ConfigDataEnvironmentContributors contributors,
260260
ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
261261
this.logger.trace("Processing config data environment contributors with initial activation context");
262-
return contributors.withProcessedImports(importer, activationContext);
262+
contributors = contributors.withProcessedImports(importer, activationContext);
263+
registerBootstrapBinder(contributors, activationContext, DENY_INACTIVE_BINDING);
264+
return contributors;
263265
}
264266

265267
private ConfigDataActivationContext withProfiles(ConfigDataEnvironmentContributors contributors,
@@ -304,7 +306,15 @@ private Collection<? extends String> getIncludedProfiles(ConfigDataEnvironmentCo
304306
private ConfigDataEnvironmentContributors processWithProfiles(ConfigDataEnvironmentContributors contributors,
305307
ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
306308
this.logger.trace("Processing config data environment contributors with profile activation context");
307-
return contributors.withProcessedImports(importer, activationContext);
309+
contributors = contributors.withProcessedImports(importer, activationContext);
310+
registerBootstrapBinder(contributors, activationContext, ALLOW_INACTIVE_BINDING);
311+
return contributors;
312+
}
313+
314+
private void registerBootstrapBinder(ConfigDataEnvironmentContributors contributors,
315+
ConfigDataActivationContext activationContext, BinderOption... binderOptions) {
316+
this.bootstrapContext.register(Binder.class, InstanceSupplier
317+
.from(() -> contributors.getBinder(activationContext, binderOptions)).withScope(Scope.PROTOTYPE));
308318
}
309319

310320
private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/ConfigDataEnvironmentPostProcessorBootstrapContextIntegrationTests.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -51,6 +51,7 @@ void bootstrapsApplicationContext() {
5151
LoaderHelper bean = context.getBean(TestConfigDataBootstrap.LoaderHelper.class);
5252
assertThat(bean).isNotNull();
5353
assertThat(bean.getBound()).isEqualTo("igotbound");
54+
assertThat(bean.getProfileBound()).isEqualTo("igotprofilebound");
5455
assertThat(bean.getLocation().getResolverHelper().getLocation())
5556
.isEqualTo(ConfigDataLocation.of("testbootstrap:test"));
5657
}

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/config/TestConfigDataBootstrap.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -121,6 +121,10 @@ String getBound() {
121121
return this.binder.get().bind("myprop", String.class).orElse(null);
122122
}
123123

124+
String getProfileBound() {
125+
return this.binder.get().bind("myprofileprop", String.class).orElse(null);
126+
}
127+
124128
@Override
125129
public void onApplicationEvent(BootstrapContextClosedEvent event) {
126130
event.getApplicationContext().getBeanFactory().registerSingleton("loaderHelper", this);
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
spring.config.import=testbootstrap:test
2+
spring.profiles.active=test
23
myprop=igotbound
4+
#---
5+
spring.config.activate.on-profile=test
6+
myprofileprop=igotprofilebound

0 commit comments

Comments
 (0)