Issue
I'm building a backend servie using spring boot. The packaging type is war.
I externalized the main application config, including RSA private keys in a file named env.properties
located at the project root folder(right next to pom.xml).
In the main application.properties
file, I have all the same fields that reference the fields in the env.properties
file.
I put application.properties
in version control, not the env.properties
.
My purpose of doing so is that I can keep the real production config away from version control and make each delopyment flexible in terms of configuration.
During development, the setup works fine, but the problem comes when I try to deploy the application. After running mvn clean build, I get a .war file, which won't start (404) when I deploy it on tomcat9. If I try to run the .war file with java -jar xxx.war, the output is
$ java -jar xxx.war
23:04:12.260 [main] DEBUG org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - Application failed to start due to an exception
org.springframework.boot.context.config.ConfigDataResourceNotFoundException: Config data resource 'file [env.properties]' via location 'file:env.properties' cannot be found
at org.springframework.boot.context.config.ConfigDataResourceNotFoundException.withLocation(ConfigDataResourceNotFoundException.java:97)
at org.springframework.boot.context.config.ConfigDataImporter.handle(ConfigDataImporter.java:145)
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:136)
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86)
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:116)
at org.springframework.boot.context.config.ConfigDataEnvironment.processInitial(ConfigDataEnvironment.java:240)
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:227)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102)
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102)
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131)
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85)
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120)
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114)
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65)
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:339)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:297)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1301)
at com.jnairport.yqpay.YqpayApplication.main(YqpayApplication.java:10)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
at org.springframework.boot.loader.WarLauncher.main(WarLauncher.java:59)
23:04:12.267 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description:
Config data resource 'file [env.properties]' via location 'file:env.properties' does not exist
Action:
Check that the value 'file:env.properties' at class path resource [application.properties] - 1:22 is correct, or prefix it with 'optional:'
It seems when I package the application for deployment, maven didn't pick up the env.properties
file. The whole app won't run at all.
I've tried to search for solutions but got no clue. Please help, thanks.
Solution
Thanks for the reply from Jakub Marchwicki, it's quite detailed. I believe it's going to help a lot of people who may have searched for a similar issue in the future.
I solved the problem by ditching the whole idea of using the env.properties file for externalized config. After some study I found a better way of using spring profiles, where I keep config files for different profiles and reference the needed one in application.properties file.
For example, I could have a application-development.properties
file and a application-production.properties
file. When in development, the first config file is referenced in the main application.properties
file whereas in production, the second one is referenced. The config file for production is not version controlled of course.
You may find this article useful: https://springframework.guru/spring-profiles/
Hope it helps, cheers!
Answered By - lightblue
Answer Checked By - Robin (JavaFixing Admin)