Skip to content

Commit 38e4c2a

Browse files
committed
Add ConfigDataEnvironmentUpdateListener support
Add an overloaded `ConfigDataEnvironmentPostProcessor.applyTo` method that accepts a listener that can used to track the updates that were applied to the `Environment`. The listener can be used to track the which `ConfigDataLocation` and the `ConfigDataResource` were used to add a `PropertySource`. The lister can also be used to tell which profiles were applied. This enhancement is being added in a patch release because it's will be useful for Spring Cloud 2020.0.0. Closes gh-24504
1 parent 5e1a69e commit 38e4c2a

File tree

8 files changed

+236
-24
lines changed

8 files changed

+236
-24
lines changed

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

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ class ConfigDataEnvironment {
119119

120120
private final Collection<String> additionalProfiles;
121121

122+
private final ConfigDataEnvironmentUpdateListener environmentUpdateListener;
123+
122124
private final ConfigDataLoaders loaders;
123125

124126
private final ConfigDataEnvironmentContributors contributors;
@@ -130,9 +132,13 @@ class ConfigDataEnvironment {
130132
* @param environment the Spring {@link Environment}.
131133
* @param resourceLoader {@link ResourceLoader} to load resource locations
132134
* @param additionalProfiles any additional profiles to activate
135+
* @param environmentUpdateListener optional
136+
* {@link ConfigDataEnvironmentUpdateListener} that can be used to track
137+
* {@link Environment} updates.
133138
*/
134139
ConfigDataEnvironment(DeferredLogFactory logFactory, ConfigurableBootstrapContext bootstrapContext,
135-
ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles) {
140+
ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles,
141+
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
136142
Binder binder = Binder.get(environment);
137143
UseLegacyConfigProcessingException.throwIfRequested(binder);
138144
this.logFactory = logFactory;
@@ -143,6 +149,8 @@ class ConfigDataEnvironment {
143149
this.environment = environment;
144150
this.resolvers = createConfigDataLocationResolvers(logFactory, bootstrapContext, binder, resourceLoader);
145151
this.additionalProfiles = additionalProfiles;
152+
this.environmentUpdateListener = (environmentUpdateListener != null) ? environmentUpdateListener
153+
: ConfigDataEnvironmentUpdateListener.NONE;
146154
this.loaders = new ConfigDataLoaders(logFactory, bootstrapContext);
147155
this.contributors = createContributors(binder);
148156
}
@@ -301,16 +309,18 @@ private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
301309
MutablePropertySources propertySources = this.environment.getPropertySources();
302310
this.logger.trace("Applying config data environment contributions");
303311
for (ConfigDataEnvironmentContributor contributor : contributors) {
304-
if (contributor.getKind() == ConfigDataEnvironmentContributor.Kind.BOUND_IMPORT
305-
&& contributor.getPropertySource() != null) {
312+
PropertySource<?> propertySource = contributor.getPropertySource();
313+
if (contributor.getKind() == ConfigDataEnvironmentContributor.Kind.BOUND_IMPORT && propertySource != null) {
306314
if (!contributor.isActive(activationContext)) {
307-
this.logger.trace(LogMessage.format("Skipping inactive property source '%s'",
308-
contributor.getPropertySource().getName()));
315+
this.logger.trace(
316+
LogMessage.format("Skipping inactive property source '%s'", propertySource.getName()));
309317
}
310318
else {
311-
this.logger.trace(LogMessage.format("Adding imported property source '%s'",
312-
contributor.getPropertySource().getName()));
313-
propertySources.addLast(contributor.getPropertySource());
319+
this.logger
320+
.trace(LogMessage.format("Adding imported property source '%s'", propertySource.getName()));
321+
propertySources.addLast(propertySource);
322+
this.environmentUpdateListener.onPropertySourceAdded(propertySource, contributor.getLocation(),
323+
contributor.getResource());
314324
}
315325
}
316326
}
@@ -320,6 +330,7 @@ private void applyToEnvironment(ConfigDataEnvironmentContributors contributors,
320330
this.environment.setDefaultProfiles(StringUtils.toStringArray(profiles.getDefault()));
321331
this.logger.trace(LogMessage.format("Setting active profiles: %s", profiles.getActive()));
322332
this.environment.setActiveProfiles(StringUtils.toStringArray(profiles.getActive()));
333+
this.environmentUpdateListener.onSetProfiles(profiles);
323334
}
324335

325336
private void checkForInvalidProperties(ConfigDataEnvironmentContributors contributors) {

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,20 @@ public class ConfigDataEnvironmentPostProcessor implements EnvironmentPostProces
6363

6464
private final ConfigurableBootstrapContext bootstrapContext;
6565

66+
private final ConfigDataEnvironmentUpdateListener environmentUpdateListener;
67+
6668
public ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,
6769
ConfigurableBootstrapContext bootstrapContext) {
70+
this(logFactory, bootstrapContext, null);
71+
}
72+
73+
public ConfigDataEnvironmentPostProcessor(DeferredLogFactory logFactory,
74+
ConfigurableBootstrapContext bootstrapContext,
75+
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
6876
this.logFactory = logFactory;
6977
this.logger = logFactory.getLog(getClass());
7078
this.bootstrapContext = bootstrapContext;
79+
this.environmentUpdateListener = environmentUpdateListener;
7180
}
7281

7382
@Override
@@ -97,7 +106,7 @@ void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader
97106
ConfigDataEnvironment getConfigDataEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
98107
Collection<String> additionalProfiles) {
99108
return new ConfigDataEnvironment(this.logFactory, this.bootstrapContext, environment, resourceLoader,
100-
additionalProfiles);
109+
additionalProfiles, this.environmentUpdateListener);
101110
}
102111

103112
private void postProcessUsingLegacyApplicationListener(ConfigurableEnvironment environment,
@@ -154,6 +163,29 @@ public static void applyTo(ConfigurableEnvironment environment, ResourceLoader r
154163
postProcessor.postProcessEnvironment(environment, resourceLoader, additionalProfiles);
155164
}
156165

166+
/**
167+
* Apply {@link ConfigData} post-processing to an existing {@link Environment}. This
168+
* method can be useful when working with an {@link Environment} that has been created
169+
* directly and not necessarily as part of a {@link SpringApplication}.
170+
* @param environment the environment to apply {@link ConfigData} to
171+
* @param resourceLoader the resource loader to use
172+
* @param bootstrapContext the bootstrap context to use or {@code null} to use a
173+
* throw-away context
174+
* @param additionalProfiles any additional profiles that should be applied
175+
* @param environmentUpdateListener optional
176+
* {@link ConfigDataEnvironmentUpdateListener} that can be used to track
177+
* {@link Environment} updates.
178+
*/
179+
public static void applyTo(ConfigurableEnvironment environment, ResourceLoader resourceLoader,
180+
ConfigurableBootstrapContext bootstrapContext, Collection<String> additionalProfiles,
181+
ConfigDataEnvironmentUpdateListener environmentUpdateListener) {
182+
DeferredLogFactory logFactory = Supplier::get;
183+
bootstrapContext = (bootstrapContext != null) ? bootstrapContext : new DefaultBootstrapContext();
184+
ConfigDataEnvironmentPostProcessor postProcessor = new ConfigDataEnvironmentPostProcessor(logFactory,
185+
bootstrapContext, environmentUpdateListener);
186+
postProcessor.postProcessEnvironment(environment, resourceLoader, additionalProfiles);
187+
}
188+
157189
@SuppressWarnings("deprecation")
158190
static class LegacyConfigFileApplicationListener extends ConfigFileApplicationListener {
159191

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.context.config;
18+
19+
import java.util.EventListener;
20+
21+
import org.springframework.core.env.Environment;
22+
import org.springframework.core.env.PropertySource;
23+
24+
/**
25+
* {@link EventListener} to listen to {@link Environment} updates triggered by the
26+
* {@link ConfigDataEnvironmentPostProcessor}.
27+
*
28+
* @author Phillip Webb
29+
* @since 2.4.2
30+
*/
31+
public interface ConfigDataEnvironmentUpdateListener extends EventListener {
32+
33+
/**
34+
* A {@link ConfigDataEnvironmentUpdateListener} that does nothing.
35+
*/
36+
ConfigDataEnvironmentUpdateListener NONE = new ConfigDataEnvironmentUpdateListener() {
37+
};
38+
39+
/**
40+
* Called when a new {@link PropertySource} is added to the {@link Environment}.
41+
* @param propertySource the {@link PropertySource} that was added
42+
* @param location the original {@link ConfigDataLocation} of the source.
43+
* @param resource the {@link ConfigDataResource} of the source.
44+
*/
45+
default void onPropertySourceAdded(PropertySource<?> propertySource, ConfigDataLocation location,
46+
ConfigDataResource resource) {
47+
}
48+
49+
/**
50+
* Called when {@link Environment} profiles are set.
51+
* @param profiles the profiles being set
52+
*/
53+
default void onSetProfiles(Profiles profiles) {
54+
}
55+
56+
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.boot.context.config;
1818

19+
import java.util.Collections;
1920
import java.util.Set;
2021
import java.util.function.Supplier;
2122

@@ -119,9 +120,13 @@ void postProcessEnvironmentWhenUseLegacyProcessingSwitchesToLegacyMethod() {
119120
@Test
120121
void applyToAppliesPostProcessing() {
121122
int before = this.environment.getPropertySources().size();
122-
ConfigDataEnvironmentPostProcessor.applyTo(this.environment, null, null, "dev");
123+
TestConfigDataEnvironmentUpdateListener listener = new TestConfigDataEnvironmentUpdateListener();
124+
ConfigDataEnvironmentPostProcessor.applyTo(this.environment, null, null, Collections.singleton("dev"),
125+
listener);
123126
assertThat(this.environment.getPropertySources().size()).isGreaterThan(before);
124127
assertThat(this.environment.getActiveProfiles()).containsExactly("dev");
128+
assertThat(listener.getAddedPropertySources()).hasSizeGreaterThan(0);
129+
assertThat(listener.getProfiles().getActive()).containsExactly("dev");
125130
}
126131

127132
}

0 commit comments

Comments
 (0)