Is it possible to load Spring-Boot properties from config folder within parent module of a Maven multi-module project?

Viewed 931

Is it possible to load multiple Spring-Boot .yml config files from a config folder within parent module of a multi-module project?

So, structure looks like this:

parent-module/
  pom.xml
  config/
    application-prd.yml
    application-dev.yml
  module1
    pom.xml
    src/main/resources/
      logback-spring.xml
      bootstrap.yml

Is this possible? How can it be done?

So, if I execute from root folder of multi-module project, I would use this command:

mvn -pl module1 spring-boot:run
   OR
mvn spring-boot:run

And I would hope that the config folder would be included in the classpath? I am trying to do this but not getting it to work. Am I missing something?

We know this to be true: Child POMs inherit properties, dependencies, and plugin configurations from the parent. But shouldn't that mean that {parent}/config/application.yml is in the classpath already?

Example project to use for proving: https://github.com/djangofan/spring-boot-maven-multi-module-example . Clone it and modify if you think you can solve it.

3 Answers

Yes, it is possible.

Maven changes the working directory to the module's directory when you use the -pl. So it is no longer the root which has the config/ dir.

Either you can refactor your maven multi-module setup to a way that you can package the common application.yml files and than use them. I wouldn't recommend that as it has many pitfalls.

Probably easier to use the --spring.config-location

$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

I can not test it at the moment but if it doesn't work you can always try the -Dspring.config.location or the SPRING_CONFIG_LOCATION environment variable.

I found a customized way of doing it, which I still consider to be a hack, as you can see below, but I am still looking for an actual answer to my question, if it exists.

@Slf4j
@SpringBootApplication
public class Application {

    private static String DEV_PROPS = "application-dev.properties";
    private static String PRD_PROPS = "application-prd.properties";
    private static String DEFAULT_PROPS = "application.properties";

    private static Path CONFIG = Paths.get(System.getProperty("user.dir"))
            .resolve(Paths.get(".."))
            .resolve("config");

    private static final String EXT_CONFIG_DIR = CONFIG.toString() + File.separator;

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer properties = new PropertySourcesPlaceholderConfigurer();
        Resource[] resources = new Resource[] {
                        new FileSystemResource(EXT_CONFIG_DIR + PRD_PROPS),
                        new FileSystemResource(EXT_CONFIG_DIR + DEV_PROPS),
                        new ClassPathResource(DEFAULT_PROPS)
                };
        log.info("Properties: " + Arrays.deepToString(resources));
        properties.setIgnoreResourceNotFound(true);
        properties.setLocations(resources);
        return properties;
    }

}

The problem with this method, is that configuration has to be changed to support additional environment profile names.

No need to write code. You can use Exec Maven Plugin for this. Add the plugin to the parent module:

<build>
  <plugins>
    <plugin>
      <groupId>org.codehaus.mojo</groupId>
      <artifactId>exec-maven-plugin</artifactId>
      <version>1.6.0</version>
      <configuration>
        <mainClass>PACKAGE.MODULE_MAIN_CLASS</mainClass>
        <arguments>
          <argument>--spring.profiles.active=dev</argument>
        </arguments>
      </configuration>
    </plugin>
  </plugins>
</build>

then run mvn install once and then mvn exec whenever you want to start the application.

mvn exec:java -pl module1

For more on Maven goals in a multi-module project, check this answer https://stackoverflow.com/a/11091569/512667 .

Another way to configure this is like so, which requires the workingDirectory arg:

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <mainClass>com.example.Application</mainClass>
        <workingDirectory>${maven.multiModuleProjectDirectory}</workingDirectory>
        <arguments>
            <argument>--spring.profiles.active=dev</argument>
        </arguments>
    </configuration>
</plugin>

In this case, execute:

mvn spring-boot:run -pl module1
Related