Spring boot external configuration in standalone jetty - spring-boot

I am building a spring boot application. I want to configure my database properties externally, so anyone can run war file from any machine. How do I configure application.properties externally? I am following this documentation http://docs.spring.io/autorepo/docs/spring-boot/1.0.1.RELEASE/reference/html/boot-features-external-config.html
So I created a app.properties file in jetty's home directory.
spring.datasource.url=jdbc:sqlserver://mymachine:1433;databasename=TESTDB
spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.username=someuser
spring.datasource.password=somepass
And trying to run war file through jetty, but it is not detecting application.properties for some reason.
java -jar ../start.jar --spring.config.location=file:///E:/Tools/jetty-distribution-9.3.12.v20160915/demo-base/webapps/app.properties
When I run above command, I get following error in jetty
Caused by:
java.lang.IllegalArgumentException: Property 'driverClassName' must not be empty
at org.springframework.util.Assert.hasText(Assert.java:168)
at org.springframework.jdbc.datasource.DriverManagerDataSource.setDriverClassName(DriverManagerDataSource.java:1
24)
at com.abc.mycompany.sts.config.settings.PersistenceContext.dataSource(PersistenceContext.java:55)
at com.abc.mycompany.sts.config.settings.PersistenceContext$$EnhancerBySpringCGLIB$$368bb66a.CGLIB$dataSource$2
(<generated>)
at com.abc.mycompany.sts.config.settings.PersistenceContext$$EnhancerBySpringCGLIB$$368bb66a$$FastClassBySpring
CGLIB$$25ca0903.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(Configurati
onClassEnhancer.java:356)
at com.abc.mycompany.sts.config.settings.PersistenceContext$$EnhancerBySpringCGLIB$$368bb66a.dataSource(<genera
ted>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy
.java:162)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolv
er.java:588)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(Ab
stractAutowireCapableBeanFactory.java:1128)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutow
ireCapableBeanFactory.java:1022)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCap
ableBeanFactory.java:512)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapab
leBeanFactory.java:482)
This is my jetty's directory structure
E:\Tools\jetty-distribution-9.3.12.v20160915\demo-base\webapps
On command line I am starting jetty by going to demo-base and running command
java -jar ../start.jar --spring.config.location=file:///E:/Tools/jetty-distribution-9.3.12.v20160915/demo-base/webapps/app.properties
The bean looks like below where I am trying to access properties from external application.properties file
#Bean
public DataSource dataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty(ConfigConstants.DATABASE_DRIVER_CLASS_NAME));
dataSource.setUrl(env.getProperty(ConfigConstants.DATABASE_URL));
dataSource.setUsername(env.getProperty(ConfigConstants.DATABASE_USERNAME));
dataSource.setPassword(env.getProperty(ConfigConstants.DATABASE_PASSWORD));
return dataSource;
}
This doesn't find my app.properties file. What am I missing?

I see you use env properties to initialize datasource and I would suggest another one solution for you.
Proposition one: it is possible to set properties value on startup like:
java -jar ../start.jar --spring.datasource.url=jdbc:sqlserver://mymachine:1433;databasename=TESTDB --spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver --spring.datasource.username=someuser --spring.datasource.password=somepass
Or if you want mask property names, define your own properties. You have to pack following application.properties file into you jar:
spring.datasource.url=${APP_DB_URL}
spring.datasource.driver-class-name=${APP_DB_DRIVER_CLASS}
spring.datasource.username=${APP_DB_USERNAME}
spring.datasource.password=${APP_DB_PASSWORD}
Next. Before run application set env properties. On *nix platform:
export APP_DB_URL=jdbc:sqlserver://mymachine:1433;databasename=TESTDB
export APP_DB_DRIVER_CLASS=com.microsoft.sqlserver.jdbc.SQLServerDriver
export APP_DB_USERNAME=someuser
export APP_DB_PASSWORD=somepass
On windows platform:
set APP_DB_URL=jdbc:sqlserver://mymachine:1433;databasename=TESTDB
set APP_DB_DRIVER_CLASS=com.microsoft.sqlserver.jdbc.SQLServerDriver
set APP_DB_USERNAME=someuser
set APP_DB_PASSWORD=somepass
And finally, just run your jar without any params:
java ../start.jar
I hope this post could be helpful for you.

Put your application.properties file under JETTY_HOME/resources folder and add
--module=resources
line to start.ini file.
Second one add resources folder to classpath, so every file under that directory will be in the classpath of your webapp.
This should work.

--spring-config-location
is not the correct property name. The property uses dot-notation, not hyphens.
Try:
--spring.config.location
For more information, see section 24.3 in the documentation: http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Additionally, you should point to the directory where the application.properties will be located instead of to the specific file. That may help, but is more useful when you later want to specify profiles. Spring Boot can then select the correct properties file base on profile. For example:
--spring.config.location=file:///E:/jetty/demo-base/webapps/
If you had multiple files in this directory like:
application.properties
application-dev.properties
application-prod.properties
You could add the
--spring.profiles.active=prod
To select the prod properties.

You have too many slashes in the path to the file after "file:" protocol and backslashes should be used too:
--spring.config.location=file:E:\Tools\jetty-distribution-9.3.12.v20160915\demo-base\webapps\app.properties

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

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

Loading properties file WebSphere Liberty

I have a simple application that uses Spring to load a properties file from the classpath. When deploying this application to WebSphere Liberty 8.5.5 it results in FileNotFoundException.
nested exception is java.io.FileNotFoundException: Could not open ServletContext resource [/myprops.properties]
Here is my spring #Configuration class:
#Configuration
#Profile("dev")
#PropertySource("classpath:/myprops.properties")
public class AppConfigDev extends AppConfig {
...
}
I am wondering where in the Liberty directory structure should my properties file reside?
The use of prefix classpath: in your annotation signifies that the given property file would be picked up from WebSphere's, well, classpath, via a ClassLoader.getResources(...) call.
Ref: http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/resources.html#resources-classpath-wildcards
You will need to create a jar of all your properties files for Websphere Liberty to be able to load them.
Ref:
1. https://developer.ibm.com/answers/questions/13384/websphere-liberty-8-5-setting-java-classpath.html
2. Websphere Liberty 8.5: Setting Java classpath
You can set the name/directory of your files in a file named jvm.options and put it in your ${server.config.dir}/jvm.options
Specific example :
In the file: ${server.config.dir}/jvm.options
Add the following line: -DAPP_ENV=PROD
Access the value with: System.getProperty("APP_ENV"); -> PROD

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