Reputation: 463
We are in the process of defining our micro service infrastructure across our company. We have created our own "parent", which defines the BOM for our services. Additionally, we have several "starter" projects and small libraries that can be used by our services. (Example, a service can include "starter-stream" to include the dependencies for Kafka).
The streaming utilities library provides its own AutoConfiguration for Kafka setup and requires that the default AutoConfiguration for Kafka to be disabled. This is straightforward, we can just require that any micro service that uses the library to add an "exclude".
What I am looking for is a way to do this programmatically, such that we do not have to add an exclude in EACH web service.
I know this is probably a unique situation, and one possible way I was thinking about doing this was adding an EnvironmentPostProcessor to our utility library that will add the exclusion to spring.autoconfigure.exclude
. We can make this smart enough to concatenate the exclusion if the property already exists.
Is there a more elegant way of doing this type of thing?
Upvotes: 3
Views: 4812
Reputation: 463
The solution we ended up landing on:
This class will create or concatenate entries to spring.autoconfigure.exclude
public class AutoConfigurationExclusion implements EnvironmentPostProcessor{
private static final String SPRING_EXCLUDE_PROPERTY = "spring.autoconfigure.exclude";
String exclusionList;
public AutoConfigurationExclusion(Class<?> ... classes) {
StringBuilder builder = new StringBuilder();
for (Class<?> clazz : classes) {
if (builder.length() > 0) {
builder.append(",");
}
builder.append(clazz.getCanonicalName());
}
exclusionList = builder.toString();
}
public AutoConfigurationExclusion(String ... classes) {
StringBuilder builder = new StringBuilder();
for (String className : classes) {
if (builder.length() > 0) {
builder.append(",");
}
builder.append(className);
}
exclusionList = builder.toString();
}
@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
String excludes = environment.getProperty(SPRING_EXCLUDE_PROPERTY);
if (StringUtils.isBlank(excludes)) {
excludes = exclusionList;
} else {
excludes = excludes + "," + exclusionList;
}
Map<String, Object> map = new HashMap<>();
map.put(SPRING_EXCLUDE_PROPERTY, excludes);
SpringPropertyOverrideHelper.overrideValues(environment.getPropertySources(), map);
}
}
And the static helper to get/create a new property source to hold the "overridden" value(s) and that source is added as the first property source.
public class SpringPropertyOverrideHelper {
private static final String PROPERTY_SOURCE_NAME = "overrideProperties";
public static void overrideValues(MutablePropertySources propertySources, Map<String, Object> propertyMap) {
MapPropertySource target = null;
if (propertySources.contains(PROPERTY_SOURCE_NAME)) {
PropertySource<?> source = propertySources.get(PROPERTY_SOURCE_NAME);
if (source instanceof MapPropertySource) {
target = (MapPropertySource) source;
for (Map.Entry<String, Object> entry : propertyMap.entrySet()) {
target.getSource().put(entry.getKey(), entry.getValue());
}
}
} else {
target = new MapPropertySource(PROPERTY_SOURCE_NAME, propertyMap);
}
if (!propertySources.contains(PROPERTY_SOURCE_NAME)) {
propertySources.addFirst(target);
}
}
private SpringPropertyOverrideHelper() {
}
}
Upvotes: 1
Reputation: 51481
I think what you suggest could be fine with an EnvironmentPostProcessor
to modify the spring.auconfigure.exclude
.
Another funky way could be is to subclass the org.springframework.boot.autoconfigure.AutoConfigurationImportSelector
and override the org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getExclusions
so that it combines already configured exclusions with the ones you add.
public class MyCustomSelector extends AutoConfigurationImportSelector {
@Override
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> exclusions = super.getExclusions(metadata, attributes);
exclusions.add("some.other.config.Configuration");
return exclusions;
}
}
and then you can just use it with @Import(MyCustomSelector.class)
.
Upvotes: 5