Spring Boot Reading Properties Files Based on classpath arg - spring

I have created a standalone boot.jar that I need to start integrating into our higher environments.
Each environment has a property file that contains database specific connection information. Since this does not live in my boot jar, I would like to somehow add the path to this database.properties file and then read the entries based on key. Used to create a bean like so:
<bean id="propertyLoader" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>classpath:application.properties</value>
</property>
but with boot, I am not sure how to do this: But I want to point to this below property example and pull out my values and somehow populate the application.properties values that I hardcoded in dev.
server:/config/database.properties
jdbc.username=TEST
jdbc.password=CHANGEME
Updating my application.properites:
spring.datasource.username='jdbc.username'
spring.datasource.password='jdbc.password'
Something like that do I can parameterize my application.properties file.

SpringBoot offers profiles, which basically allows you to have separate application.properties file for each environment.
You can have something like this:
public interface DataSourceConfig {}
#Component
#Profile("dev")
public DevDataSourceConfig implements DataSourceConfig{}
#Component
#Profile("prod")
public ProdDataSourceConfig implements DataSourceConfig{}
If you have the spring profile "dev" set as active, only the DevDataSourceConfig bean will be instantiated and in Spring Environment the properties that will be injected, will be read from the application-dev.properties file.
Similarly when you have the "prod" profile activated, only the ProdDataSourceConfig will be instantiated and the properties will be loaded from application-prod.properties file.
This allows you to have:
---
application-dev.properties
spring.datasource.username='jdbc.username'
spring.datasource.password='jdbc.password'
---
application-prod.properties
spring.datasource.username='PROD_jdbc.username'
spring.datasource.password='PROD_jdbc.password'
If you want to load the configuration from a custom location on the file system - you can check how to pass the location with command line arguments (docs)
Example:
java -jar boot.jar --spring.config.location=classpath:/database.properties

you already told you can not have property files inside your jar, still there are multiple options.
1> passing a property file for respective env.
java -jar myproject.jar --spring.config.location=classpath:/database.properties
2> pass properties while calling the jar
java -jar app.jar --spring.datasource.username="jdbc.username" --spring.datasource.password="jdbc.password"
Read a lot of other options here `
I would go with option 1, because passing credentials is never advisable in arguements.

Related

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.

Externalize password in Spring Boot properties file

i have application.properties file
which has
spring.profiles.active=local
and i have application-local.properties which has many fields including
api.password = password123
As you can see i have hard coded password123 in properties file.
Suppose i am on windows and i have app.properties file on windows which has
api.password = password123
And i want to read api.password in spring boot properties file through app.properties
How can i achieve it ?
Startup parameters
If you want to read properties from a non-standard location, you can start your application with --spring.config.location or with --spring.config.additional-location parameters.
$ java -jar app.jar --spring.config.location=file:./app.properties
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-application-property-files
#PropertySource
If you don't control startup parameters, you can use #PropertySource annotation.
Simply annotate your main class (or any other configuration):
#PropertySource("file:.app.properties")
You can set ignoreResourceNotFound=true, so the application will start, even if the file is not there.
https://docs.spring.io/spring/docs/5.1.9.RELEASE/javadoc-api/org/springframework/context/annotation/PropertySource.html
Read the documentation
There are literally 17 ways to pass properties to a Spring-Boot application.
I suggest, you get familiar with the convention, as it is crucial to understand which file takes a precedence:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config
Probably you can use --spring.config.location like below
$ java -jar myApp.jar --spring.config.location=file:/directoryof file/app.properties
i used jasypt : https://github.com/ulisesbocchio/jasypt-spring-boot
to encrypt the password, then you supply a decryption string (jasypt.encryptor.password) as startup parameter. That way no useabel password is in the configuration and on the git-repos.....

SpringBoot: Separate property files

I've created my application.properties file:
spring.config.additional-location=C:\Users\user\
spring.datasource.url=jdbc:postgresql://<db>:<port>/<db>
I need to feed Spring with an additional file located on C:\Users\user\application.properties:
spring.datasource.username=user
spring.datasource.password=password
As you can see I've tried to use spring.config.additional-location property into my application.properties file.
However, bootstrap tells me that no authentication has been provided.
you can use another file name by specifying a spring.config.name environment property. You can also refer to an explicit location by using the spring.config.location environment property (which is a comma-separated list of directory locations or file paths). The following example shows how to specify a different file name:
$ java -jar myproject.jar --spring.config.name=myproject
Reference URL:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
You can specify your alternative properties using #PropertySources like this:
#PropertySources({
#PropertySource({"classpath:application.properties"}),
#PropertySource(value = {"file:${conf-dir}}/application-override.properties" },ignoreResourceNotFound = true)
})
public class AppConfig {
...
The properties in the bottom PropertySource will override properties from first one, if the file exists.
The documentation says to use file:C:/Users/user/
the "file:" or "classpath:" part is important.
There are numerous other ways to do this, too.
- profiles (and per profile application-<profile>.properties)
- #Configuration + #PropertySource
- ...

Spring boot on Tomcat with external configuration

I can't find an answer to this question on stackoverflow hence im asking here so I could get some ideas.
I have a Spring Boot application that I have deployed as a war package on Tomcat 8. I followed this guide Create a deployable war file which seems to work just fine.
However the issue I am currently having is being able to externalize the configuration so I can manage the configuration as puppet templates.
In the project what I have is,
src/main/resources
-- config/application.yml
-- config/application.dev.yml
-- config/application.prod.yml
-- logback-spring.yml
So how can I possibly load config/application.dev.yml and config/application.prod.yml externally and still keep config/application.yml ? (contains default properties including spring.application.name)
I have read that the configuration is load in this order,
A /config subdirectory of the current directory.
The current directory
A classpath /config package
The classpath root
Hence I tried to load the configuration files from /opt/apache-tomcat/lib to no avail.
What worked so far
Loading via export CATALINA_OPTS="-Dspring.config.location=/opt/apache-tomcat/lib/application.dev.yml"
however what I would like to know is,
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
And is there a better method to achieve this ?
You are correct about load order. According to 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).
[Note]
You can also use YAML ('.yml') files as an alternative to '.properties'.
This means that if you place your application.yml file to /opt/apache-tomcat/lib or /opt/apache-tomcat/lib/config it will get loaded.
Find out why loading via /opt/apache-tomcat/lib classpath doesn't work.
However, if you place application.dev.yml to that path, it will not be loaded because application.dev.yml is not filename Spring is looking for. If you want Spring to read that file as well, you need to give it as option
--spring.config.name=application.dev or -Dspring.config.name=application.dev.
But I do not suggest this method.
And is there a better method to achieve this ?
Yes. Use Spring profile-specific properties. You can rename your files from application.dev.yml to application-dev.yml, and give -Dspring.profiles.active=dev option. Spring will read both application-dev.yml and application.yml files, and profile specific configuration will overwrite default configuration.
I would suggest adding -Dspring.profiles.active=dev (or prod) to CATALINA_OPTS on each corresponding server/tomcat instance.
I have finally simplified solution for reading custom properties from external location i.e outside of the spring boot project. Please refer to below steps.
Note: This Solution created and executed windows.Few commands and folders naming convention may vary if you are deploying application on other operating system like Linux..etc.
1. Create a folder in suitable drive.
eg: D:/boot-ext-config
2. Create a .properties file in above created folder with relevant property key/values and name it as you wish.I created dev.properties for testing purpose.
eg :D:/boot-ext-config/dev.properties
sample values:
dev.hostname=www.example.com
3. Create a java class in your application as below
------------------------------------------------------
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
#PropertySource("classpath:dev.properties")
#ConfigurationProperties("dev")
public class ConfigProperties {
private String hostname;
//setters and getters
}
--------------------------------------------
4. Add #EnableConfigurationProperties(ConfigProperties.class) to SpringBootApplication as below
--------------------------------------------
#SpringBootApplication
#EnableConfigurationProperties(ConfigProperties.class)
public class RestClientApplication {
public static void main(String[] args) {
SpringApplication.run(RestClientApplication.class, args);
}
}
---------------------------------------------------------
5. In Controller classes we can inject the instance using #Autowired and fetch properties
#Autowired
private ConfigProperties configProperties;
and access properties using getter method
System.out.println("**********hostName******+configProperties.getHostName());
Build your spring boot maven project and run the below command to start application.
-> set SPRING_CONFIG_LOCATION=<path to your properties file>
->java -jar app-name.jar

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).

Resources