nachteil
nachteil

Reputation: 452

Spring Boot executable jar and external configuration file

I have a Spring Boot application that uses 3rd-party jar. This jar requires an xml config file, that must be provided by clients on runtime (individually) and cannot be pre-packaged. 3rd party lib loads that file using below sequence (I stripped ifs and null-checks):

    FileConfigurator.class.getResource("/" + filename);
    Thread.currentThread().getContextClassLoader().getResource("/" + filename);
    Thread.currentThread().getContextClassLoader().getResource(filename);

I cannot change the way that lib loads the file (e.g. using Spring's Resource loading), so it must be on classpath. Therefore I seem to lose the possibility of executing it like java -jar my-spring-boot-app.jar, because -jar option prevents any additional classpath entries from being added. So I started running it like

java -classpath my-spring-boot-app.jar:./config/: org.springframework.boot.loader.JarLauncher

My directory structure is following:

|-- config
|   |-- application.properties
|   `-- 3rd-party-config.xml
|-- my-spring-boot-app.jar

But then Spring's autowiring started to fail: Additional application.properties file in config directory overrides some of settings and using above command causes app startup to fail:

Error creating bean with name 'ORBConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private java.lang.String com.company.app.communication.corba.orb.ORBConfig.serverName; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'application.corba.serverName' in string value "${application.corba.serverName}"

Field String serverName is annotated with @Value("${application.corba.serverName}"), the property is defined in application.properties file bundled within JAR and value injection works fine when additional application.properties is not present in config dir.

My actual question is: what is the advisable way of deploying and/or running Spring Boot application, to take advantage of executable Jar feature, provide additional classpath resources on runtime and still be able to override some (but not all) properties by classpath application.properties file?

Application is packaged using spring boot maven plugin and uses spring-boot-starter-parent parent POM.

Upvotes: 3

Views: 3947

Answers (1)

tan9
tan9

Reputation: 3620

One simple answer if you won't change the startup command:

move ./config/application.properties to ./config/config/application.properties

If there exist more than one classpath resources with same name, Spring Boot will load only one of them, in you case, Spring Boot load and prioritize property resources as following:

  1. file:config/application.properties
  2. classpath:application.properties which maybe resolved to either my-spring-boot-app.jar!/applcation.properties or ./config/application.properties

If your classLoader chosen ./config/application.properties as second property source. Bang!

Spring Boot's default configuration property resource path priority (highest to lowest precedence) is:

  1. file:config/
  2. file:
  3. classpath:config/
  4. classpath

The ordinary executable jar execution make those two configuration property fall into:

  1. file:config/application.properties
  2. classpath:application.properties (from jar)

And moving ./config/application.propertie to './config/config/application.properties' becomes:

  1. classpath:config/application.properties
  2. classpath:application.properties (from jar)

Both in the same order and have no ambiguous.

Upvotes: 0

Related Questions