25

If I create a commons library having an application.properties defining common configurations. Like:

spring.main.banner-mode=off

How can I inherit these properties into another project where I include those commons library?

Maven:

<project ...>
    <groupId>de.mydomain</groupId>
    <artifactId>my-core</artifactId>
    <version>1.0.0</version>

    <dependencies>
        <dependency>
            <!-- this one holds the common application.properties -->
            <groupId>my.domain</groupId>
            <artifactId>my-commons</artifactId>
            <version>1.0.0</version>
        </dependency>
    </dependencies>
</project>

How can I inherit the configuration from my-commons to my-core?

membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • 1
    I don't think you should actually inherit properties. IMO, it is to risky. If you think about it, what happens if you inherit the same property from two differents dependencies ? How can you detect these conflicts ? – Mickael Jun 23 '17 at 10:14
  • Well, but how could I then add configurations that should apply to all of my projects. Imagine I want to define a company-wide commons project, that sets eg the `Logger` to use, a common `MailSender`, xml configuration etc. Each project inheriting from it should be forced to use this config... Also `spring-boot` itself somehow manages it to define default properties. And they can even be overridden. But how do they achieve this? – membersound Jun 23 '17 at 10:28
  • @membersound you got the answer? – soorapadman Jun 23 '17 at 11:36
  • You mean below? Yes, but did not work. – membersound Jun 23 '17 at 12:09
  • You created a library with Spring-Boot and used application.properties ?? The library to include in a project is something static that is not stand alone launchable | => you should not use this approach. In other case you can just include the library(project) itself into your main one. Of course this is only my opinion. – Lazar Lazarov Jun 23 '17 at 12:38

3 Answers3

19

Solution is to include the shared properties using a different name, here application-shared.properties

In shared library:

@SpringBootApplication
@PropertySource(ResourceUtils.CLASSPATH_URL_PREFIX + "application-shared.properties") //can be overridden by application.properties
public class SharedAutoConfiguration {
}

In main app:

@SpringBootApplication
@Import(SharedAutoConfiguration.class)
public class MainAppConfiguration extends SpringBootServletInitializer {

}

This way the commons/shared config gets loaded, but is though able to be overridden in application.properties of main app.

It does not work with the spring.main.banner-mode property (don't know why), but with all other properties it worked well.

membersound
  • 81,582
  • 193
  • 585
  • 1,120
  • 4
    Note that this works only for .properties files, not for .yml files. https://stackoverflow.com/a/41984422/2187042 – Richard Tingle Nov 23 '17 at 14:03
  • 1
    According to the latest Spring Boot docs, "Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins." – dansomething Oct 13 '20 at 16:51
1

I had a same motivation - to extract common configuration for typical service into a separate starter/library. I've decided to move with EnvironmentPostProcessor

My commons-web library has its own application-web.properties with, lets say, single property:

spring.main.banner-mode: off

And EnvironmentPostProcessor to pick it up

public class DefaultPropertiesEnvironmentPostProcessor implements EnvironmentPostProcessor {

  @SneakyThrows
  @Override
  public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    environment.getPropertySources()
        .addLast(new ResourcePropertySource("application-web.properties"));
  }

}

To make it works you need to specify a post processor (on a library side) in resources/META-INF/spring.factories this way:

org.springframework.boot.env.EnvironmentPostProcessor=\
     com.surprise.starter.web.properties.DefaultPropertiesEnvironmentPostProcessor

With such solution it's possible to pick up this config on service side and override it in regular application.properties


I'm not using @PropertySource cause there is nuance with properties ordering & detection:

...

@PropertySource annotations on your @Configuration classes. Please note that such property sources are not added to the Environment until the application context is being refreshed. This is too late to configure certain properties such as logging.* and spring.main.* which are read before refresh begins.

Silk0vsky
  • 941
  • 1
  • 18
  • 34
0

You can try this with Spring.

You can define your src/main/resources/application.properties in a common module as you mentionned. It will be present in classpath for other project that depends on it.

Then with Annotation @PropertySource, in other projects that depends on common module :

@Configuration
@PropertySource("classpath*:META-INF/spring/properties/*.properties")
public class Config {
  ...
}

Or with XML configuration :

<context:property-placeholder location="classpath*:META-INF/spring/properties/*.properties"/>

It should import all the configuration files in the give classpath directory.

Also, you should be aware that you can't have two same files in classpath. You will have a conflict.

For instance, this situation will generate a conflict :

Project A (depends on Project B) :

  • src/main/resources/application.properties

Project B :

  • src/main/resources/application.properties

You will have to rename application.properties file or to put it in a different directory.

Mickael
  • 4,458
  • 2
  • 28
  • 40
  • Your solution will work for this case .If the properties reside in resource file it's enough to say `classpath*:spring/application.properties` – soorapadman Jun 23 '17 at 11:10
  • I tried as follows: `@PropertySource("classpath:application-commons.properties")` in my commons project. But it does not work. The spring-banner is still printed (means: the property is not loaded). – membersound Jun 23 '17 at 12:08