0

I understand how to configure spring-boot and it provides a mature and sensible overriding mechanism that is documented well but I'm converting an application that gets its configuration from other source that is not in line with the spring-boot mechanism.

Ultimately the application makes properties available to the code that can be bound in using @Value("$the.prop.key:default") or used in spring xml config. The way that these properties are retrieved and bound cannot be changed.

I am trying to configure the embedded tomcat server port but the only way I can do this is using application.properties. I can change this to a different file and even change the location but I cannot change the mechanism (it has to be a file).

Looking into the spring-boot code I see it uses the notion of EmbeddedServletContainerCustomizer implementations to set these properties. Fine, I will create an implementation and set the server properties using this. But unfortunately you get 2 implementations trying to do the same thing ServerProperties and my implementation. The code orders these but because ServerProperties has not ordering it is set to the lowest priority and a low priority gets executed last and so my implementation gets overwritten.

Instead I have implemented a BeanPostProcessor:

@Named
public class SpringBootCustomConfigurator implements BeanPostProcessor {

@Value("$the.prop.key:8080")
private int port;

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
    if (bean instanceof ServerProperties) {
        ServerProperties serverProperties = (ServerProperties) bean;
        serverProperties.setPort(port);
    }
    return bean;
}
}

This does what I need to do but it isn't a satisfactory implementation. Any thoughts?

Paul
  • 29
  • 8

1 Answers1

0

Given that it's about a new source of external properties, I think it would be more natural to write an ApplicationContextInitializer (or ApplicationListener to listen for one of the Spring Boot events on startup) that adds a new PropertySource to your Environment in the right place. You can register initalizers with the SpringApplication or using META-INF/spring.factories.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • I'll try this but I suspect even with a working implementation I wont be able to use this. The problem being that the other configuration is centralised and relates to many applications. Unless I can prefix or namespace the spring-boot properties then I wont be able to use them. I can't have a centralised configuration with server.port as the key. – Paul May 07 '14 at 11:44
  • 1
    You can set server.port=${your.funny.value:8080} though. That would work. – Dave Syer May 07 '14 at 14:33
  • I think I'm getting really close. I'm just struggling to get the new propertysource added to the environment at the correct point. It turns out the that legacy global configuration uses apache commons configuration (configured in spring.xml through CommonsConfigurationFactoryBean) using a rest service to get config. If I try and get a reference to this bean in any of the spring-boot listeners then I get an illegal state exception as the context has not been refreshed yet. continued... – Paul May 08 '14 at 08:27
  • I need to add the source to the environment just before all the context gets created but it needs access to the context (doesn't seem possible). I think I need some sort of deferred property source that when it is asked for its properties it resolves to access the commons configuration – Paul May 08 '14 at 08:30
  • You could cheat and add a `@Bean` (via autoconfiguration if you want it to be available with zero config) that gets instantiated really early (like a `BeanFactoryPostProcessor`). I don't see a way round that unless you can maybe use a parent context to configure the commons config factory. – Dave Syer May 08 '14 at 12:43
  • BeanFactoryPostProcessor worked and I was able to add the property source to the environment. I would have preferred to use a parent context but there were other non-related issues with this. – Paul May 09 '14 at 08:11