Load application.properties outside jar - spring-boot

How can I set application.properties in SpringBoot outside .jar? I would link to this file and load properties from code.

By convention, Spring Boot looks for an externalized configuration file – application.properties or application.yml – in 4 predetermined locations in the following order of precedence:
/config subdirectory of the current directory
The current directory
classpath /config package
The classpath root
You can place your application.properties in any of the 4 locations without needing to give the location of application.properties while executing the jar. If you want to given any other custom location , then you will have to provide the path of the config location while executing the jar:
java -jar -Dspring.config.location=<path-to-file> myProject.jar
Source: https://www.baeldung.com/spring-properties-file-outside-jar

Related

How to make #SpringBootTest use application.properties from external config folder (inside project root)?

I have a multi-module Spring Boot Gradle project (Kotlin) with the following directory structure.
root
|- domain (Module containing entities and interfaces)
|- application (Spring boot Kotlin application)
|- src/main
|- kotlin (app sources)
|- resources
|- application.properties (default config)
|- src/test/kotlin/long/package/name/ApplicationTests.kt
|- build.gradle.kts (and also gradle folder)
|- config
|- application.properties (config to override classpath properties)
|- build.gradle.kts (and settings.gradle.kts and other gradle folder)
When I run the Application.kt file, it is able to pick up this file (both with IDE and gradle), and it runs successfully.
Since my config folder is outside my application folder, running my ApplicationTests.kt results in the error below. The output is same when running through IDE (IntelliJ) run button and ./gradlew clean test.
org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection
I am expecting the tests to find the application.properties file inside the config folder. How can I register my config/application.properties so that I can keep it separate from my classpath:application.properties?
UPDATE:
I tried adding the following copy task to gradle.
tasks.create("copy", Copy::class.java) {
from("../config")
into("$buildDir/resources/main")
}
tasks.named("test").configure {
dependsOn("copy")
}
This enables me to overwrite the application.properties from config folder (meaning any property not added in config/app.prop is no longer present). Test runs successfully now (if I add all entries from classpath properties to config/app.props). How can I merge the contents of these two properties files inside application/build.gradle.kts?
If you want to override your application.properties with an external application.properties, you can copy the external file to build/classes directory using Gradle and append a profile name, like application-ext.properties. Then, activate default and ext profiles using spring.profiles.active.
Another option would be to use Spring Config server, but that may be overkill for this simple task.
By default, Spring will look in your current working directory for the directory named, config. As you've noted, you're not executing the application in the directory containing the config directory. You can override where Spring looks for this config folder with the -Dspring.config.location option or via the environment variable, SPRING_CONFIG_LOCATION
If your config directory is located at /opt/myconfigs/config, you would start your service with -Dspring.config.location=/opt/myconfigs/config. Another option is to export SPRING_CONFIG_LOCATION=/opt/myconfigs/config and start your app without any additional JVM options.
If you're running tests in the application directory, then the config folder would be one level up from the current working directory. Annotating your tests with
#TestPropertySource(properties = "spring.config.location=../config/,classpath:/application.properties") would load the application.properties from both the config folder and the src/main/resources folder, properties in the config props would override properties in the local application properties.
The same thing can be achieved with the VM argument of -Dspring.config.location=classpath:/application.yml,file:../config/, here order is important.

Give external path in #Value Spring annotation and Resource

In spring boot application how do I give an external windows path using #Value Spring annotation and Resource
The below example works fine that look into resources folder but I want to give the path outside of application like c:\data\sample2.csv
#Value("classPath:/sample2.csv")
private Resource inputResource;
...
#Bean
public FlatFileItemReader<Employee> reader() {
FlatFileItemReader<Employee> itemReader = new FlatFileItemReader<Employee>();
itemReader.setLineMapper(lineMapper());
itemReader.setLinesToSkip(1);
itemReader.setResource(inputResource);
and if I want to get the value from properties file in annotaion, whats the format to put the path in windows?
i tried these, none of them worked:
in code
#Value("${inputfile}")
in properties file:
inputfile="C:\Users\termine\dev\sample2.csv"
inputfile="\\C:\\Users\\termine\\dev\\sample2.csv"
inputfile="C:/Users/termine/dev/sample2.csv"
inputfile="file:\\C:\Users\termine\dev\sample2.csv"
inputfile="file://C://Users//termine///dev//sample2.csv"
When you use classpath spring will try to search with the classpath even if you provide the outside file path.
so instead of using classpath: you can use file:
Ex.
#Value("file:/sample2.csv") //provide full file path if any
Use the key spring.config.location in properties to set the config location. Spring-boot will by default load properties from the locations, with precedence like below :
A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root
and apart from this when you start the jar or in application.properties you can provide the location of the config file like :
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
You can serve static files from the local disk, by making the resource(s) "sample2.csv" as a static resource. An easy way to do this is by adding spring.resources.static-locations configuration to your applicaiton.properties file. Example:
spring.resources.static-locations=file:///C:/Temp/whatever/path/sample2.csv",classpath:/static-files, classpath:/more-static-resource
When I did this in one of the projects, I was able to access the file form the browser using localhost:8080/sample2.csv.

How to parameterize the search-locations path to be reusable in other config files

I have different files (yml & xml files) where I'm hardcoding the same folder path containing my configuration files. I want to parameterize this path, so I can be able to move my configuration and modifying my parameter only once.
My bootstrap.yml :
...
cloud:
config:
failFast: true
server:
bootstrap: true
prefix: /config
native:
search-locations: file:///C:/dev/workspace/application/config/{profile}
My application-dev.yml :
...
logging:
config: file:///C:/dev/workspace/application/config/{profile}/log4j2-dev.xml
My integration-config.xml :
<context:property-placeholder location="file:///C:/dev/workspace/application/config/${spring.profiles.active}/application-${spring.profiles.active}.properties" />
How can I achieve that ? What's the best practice in this case ? Or is it even good practice to parameterize the search-locations path for the Spring Config Server File System ?
First say I'm almost not use configuration file (yml properties xml...) directly in local-file-system(outside classpath) even for local test. And for spring-cloud-config what if you using remote location to contains config, question may different.
Second, did you using some project manager tool like maven or gradle? as maven is the default tool for spring-boot projects' build in my mind. And for maven there has plugin like Maven Resources Plugin to parameterize your config variable to pom.xml which can help you modifying parameter only once for all variable in one file in build step, and same as gradle.
For spring-cloud-config, it is possible to move your almost all configuration properties to it. Means that you can move your config properties from application-dev.yml and integration-config.xml to spring-cloud-config's config file which in your case is file:///C:/dev/workspace/application/config/{profile} and it will load as env variables in runtime for spring autoconfigure or which you can #Autowired to your Environment what if you want get it manually.

Overriding spring properties in application.properties that is part of a jar

I'm developing a spring boot application(Let's call this MyLib). It uses spring-cloud-stream. The idea is that this application will be used as a jar by another java application(Let's call this MyApp. It may not be a spring boot). What I'm trying to do is that MyApp will specify the spring.cloud.stream.bindings.<channel>.destination which will be used by the code inside MyLib.
Is this achievable?
Load application.properties from an external jar
I don't know about spring.cloud.stream.bindings specifically, however a spring Boot application can load its application-${profile}.properties from multiple locations including jars on the classpath:
Spring Boot documentation:
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment:
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
The list is ordered by precedence (properties defined in locations
higher in the list override those defined in lower locations).
...
The default search path
classpath:,classpath:/config,file:,file:config/ is always used,
irrespective of the value of spring.config.location
In other words, the application-${profile}.properties file must be at ./ or ./config/ inside your MyApp.jar.
You may also define additional lookup folders with spring.config.location, however this must be done at runtime:
spring.config.name and spring.config.location are used very early to determine which files
have to be loaded so they have to be defined as an environment
property (typically OS env, system property or command line argument).
Lookup order
You mentioned
:
Overriding spring properties in application.properties
The order with which the properties are considered is the following (from spring documentation):
#TestPropertySource annotations on your tests.
Command line arguments.
Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property)
ServletConfig init parameters.
ServletContext init parameters.
JNDI attributes from java:comp/env.
Java System properties (System.getProperties()).
OS environment variables.
A RandomValuePropertySource that only has properties in random.*.
Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants)
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants)
Application properties outside of your packaged jar (application.properties and YAML variants).
Application properties packaged inside your jar (application.properties and YAML variants).
#PropertySource annotations on your #Configuration classes.
Default properties (specified using SpringApplication.setDefaultProperties).

Spring Boot and external configurations

I am trying to make a Spring Boot application. Everything is fine once I deploy to the fat jar file with everything contained in it. But, what I actually want is the configuration files to be located externally. for example I have the following directory structure:
bin - contains startup and shutdown scripts
conf - all configurations. i.e. application.properties, logback.xml i18n.properties
logs - log files
libs - app.jar
If I use this directory structure and execute the jar using
java -cp ./conf -jar ../libs/app.jar
then the properties in the conf directory are not loaded or recognized. Is there a better way to do this maintaining the directory structure above? Or, what is the alternative/best practice?
Boot external config is what you are looking for.
Especially it mentions:
SpringApplication will load properties from application.properties
files in the following locations and add them to the Spring
Environment:
A /config subdir of the current directory.
The current directory
A classpath /config package
The classpath root
So I would say adding the config folder on classpath is good step. Them it should find application.properties and load it automatically.
For different config files I use:
#Configuration
#EnableAutoConfiguration
#PropertySource({
"classpath:path/some.properties",
"classpath:another/path/xmlProperties.xml"
})
public class MyConfiguration {
// ...
}
Edit:
As Dave pointed out (Thank Dave!) there is either -cp or -jar, so you can't add it to classpath like that. But there are options. This should help you to solve the problem: Call "java -jar MyFile.jar" with additional classpath option.
Additionally #PropertySource doesn't require the resources to be classpath resources if I'm not mistaken.
It should also be mentioned that there is a spring.config.location parameter that allows one to specify a file system / classpath location for externalized configuration files. This is documented in the following section of the Spring Boot reference guide:
http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files

Resources