Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring Cloud Consul does not work well with application context hierarchies and profiles #811

Open
aaronjwhiteside opened this issue Mar 15, 2023 · 0 comments

Comments

@aaronjwhiteside
Copy link

aaronjwhiteside commented Mar 15, 2023

Describe the bug
Spring Cloud Consul: 3.0.4
Spring Boot: 2.5.14
Java: 11

Given the following application context hierarchy:

        final SpringApplicationBuilder parentBuilder = new SpringApplicationBuilder()
                .profiles("A")
                .web(WebApplicationType.NONE);
        parentBuilder.run(args);

        parentBuilder.child(BootstrapApplication.class)
                .web(WebApplicationType.NONE)
                .profiles("A", "B")
                .run(args)
                .close();

        parentBuilder.child(ApplicationConfiguration.class)
                .profiles("A")
                .web(WebApplicationType.SERVLET)
                .run(args);

And given that ConsulPropertySourceLocator is a singleton in the bootstrap context, when the empty parent context (parentBuilder) is loaded it's Environment contains the following ConsulPropertySource's:

0 = "config/service,A/"
1 = "config/service/"
2 = "config/application,A/"
3 = "config/application/"

This is all good and normal, but when the second context is loaded, it's Environment contains the following ConsulPropertySource's:

0 = "config/service,A/"
1 = "config/service/"
2 = "config/application,A/"
3 = "config/application/"
4 = "config/service,A/"
5 = "config/service,B/"
6 = "config/service/"
7 = "config/application,A/"
8 = "config/application,B/"
9 = "config/application/"

The problem is that the ConsulPropertySourceLocator is caching Consul context's from the previous ApplicationContext and just appending them together. And properties from the "B" profile that override properties from the "default" profile are not being picked up.

The current workaround I have, which is very much a hack is a @BoostrapConfiguration class that registers a BeanPostProcessor to wrap the ConsulPropertySourceLocator and clear() the context's before the next invocation of locate() is called.

@BootstrapConfiguration
public class FixConsulPropertySourceLocatorBootstrapConfiguration {
    @Bean
    public BeanPostProcessor fixConsulPropertySourceLocatorBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
                if (bean instanceof ConsulPropertySourceLocator) {
                    return new FixedConsulPropertySourceLocator((ConsulPropertySourceLocator) bean);
                } else {
                    return bean;
                }
            }
        };
    }
    
    static class FixedConsulPropertySourceLocator implements PropertySourceLocator, ConsulConfigIndexes {
        private final ConsulPropertySourceLocator delegate;
        public FixedConsulPropertySourceLocator(final ConsulPropertySourceLocator delegate) {
            this.delegate = delegate;
        }

        @Override
        public PropertySource<?> locate(final Environment environment) {
            delegate.getContexts().clear();
            return delegate.locate(environment);
        }

        @Override
        public LinkedHashMap<String, Long> getIndexes() {
            return delegate.getIndexes();
        }
    }
}

It would be nice if this was fixed upstream and in a better manor than I have attempted here.

This then makes the ConsulPropertySource's for that Environment appear as expected:

0 = "config/service,A/"
1 = "config/service,B/"
2 = "config/service/"
3 = "config/application,A/"
4 = "config/application,B/"
5 = "config/application/"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants