spring boot external config - java

I am trying to load an external properties file into my spring boot app.
initially I used #PropertySource in the config class.
but now I want to remove this annotation so the class is not dependent on the location.
so I tried to use:
java -jar my-boot-ws.war --SPRING_CONFIG_NAME=file:///Users/TMP/resources/
based on this http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html documentation but I get the following error:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder
using the annotation works fine but I would really like to move away from that.
any help on this would be great
Thanks
****** CORRECTION *******
Sorry copy paste error the above command was supposed to be:
java -jar my-boot-ws.war --spring.config.location=file:///Users/TMP/resources/
I'm not trying to change the name of the config file just add an additional location.
As explained here:
If spring.config.location contains directories (as opposed to files)
they should end in / (and will be appended with the names generated
from spring.config.name before being loaded).
I interpreted this as saying that the file ${spring.application.name}.properties would be loaded from the --spring.config.location passed in from the command line

After some more googeling I found this Spring Boot and multiple external configuration files indicating that the following is the correct usage:
java -jar my-boot-ws.war --spring.config.location=file:///Users/TMP/resources/myFile.properties
I was under the impression that the --spring.config.location would load other properties files in the directory specified. according to the post at the link I mentioned this is not the case. based on the link if the directory is specified then that is where the application.properties is searched for. but again the documentation here http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html seems to insinuate that the spring boot app will look on the class path first and if available grab the app name to get additional properties files based on that name.
however once I specified a file name everything worked fine so I guess I was mistaken.

In command line you should use below property to mention an additional boot configuration file:
--spring.config.location="file:/path/to/application.properties"
An alternative would be:
-Dspring.config.location="file:/path/to/application.properties"
Note that characters are lower case and the word separator is a period ..
Otherwise you can use an environment variable with key you used already:
In a *nix system:
export SPRING_CONFIG_NAME=file:/path/to/application.properties
In Windows OS:
set SPRING_CONFIG_NAME=file:/path/to/application.properties

It might not be a common issue, but I faced it. You also must have an application.properties inside your classpath even when you replace it with --spring.config.name (I had mine in gitignore due to sensitive information).

1) Makesure args pass inside of run method
public class GemFireTestLoaderApplication {
public static void main(String[] args) {
SpringApplication.run(GemFireTestLoaderApplication.class, args);
}
}
2) If you have configureed in xml comment or remove first
<!-- <context:property-placeholder location="classpath:config.properties" /> -->
<!-- <context:property-placeholder location="file:/data/xxx/vaquarkhan/dataLoader/config.properties" /> -->
Following command you can use to pass properties name
3.1)
java -jar GemfireTest-0.0.1-SNAPSHOT.jar --spring.config.location=file:///C:/data/xxx/vaquarkhan/dataLoader/test/config.properties
3.2)
java -jar GemfireTest-0.0.1-SNAPSHOT.jar --spring.config.location=file:///C:/data/xxx/vaquarkhan/dataLoader/test/config.properties
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

spring.config.name=spring
spring.config.location=classpath:/config/
in side the config folder spring.properties file is available, while running the server the this properties file is not loading

Related

spring boot external config with sensitive information not working

I am trying to load an external yml file into my spring boot app
On my classpath, I have 3 yml files for dev prod and tls profiles.
What I intend to do is to load an external file with the name "secret.yml" to override the values on the application-{profiles}.yml file.
This "secret.yml" file contains sensetive information. It will be add to gitignore file.
After some tries, I founded that spring not override the values inside the classpath only if I change the name to application-{profiles}.yml and not secret.yml
I tried to add spring.config.name=secret but that not working for me.
./mvnw -Dmaven.test.skip=true -Dspring.config.additional-location=file:./secret.yml -Dspring.config.name=secret.yml
Have you any solution for that issue ?
[UPDATE]
I do export environment variable export secret="secret.yml"
and then pass the variable to my command line
./mvnw -Dmaven.test.skip=true -Dspring.config.additional-location=file:./secret -Dspring.config.name=secret
Nothing changed
if you pass multiple config file, take care the order, the last one will be override to previous config sequentially.
-Dspring.config.location=classpath:application-1.yaml,classpath:application-2.yaml .. other config
the value of application-2.yaml will be override into application-1.yaml if they have same config.
**That will be merged for different config.
Try to use a absolute path as on spring boot documentation:
java -jar app.jar --spring.config.name=application --spring.config.location=file:///Users/home/secret
If you don't know the absolute path you can find it with pwd command.
All propsitions here works if I wrap my command line to jvmArguments.
./mvnw -Dspring-boot.run.jvmArguments="-Dspring.config.additional-location=file:./secrets.yml"
Thank you for all your reply

#PropertySource cannot be opened because it does not exist

I have the problem with configuration file that is located in other directory than my jar file.
I use #PropertySource for loading properties.
#PropertySource(ignoreResourceNotFound = true, value = "${ext.properties.dir:classpath:}/properties.properties")
I try to run jar using following command:
java -jar import-0.0.1-SNAPSHOT.jar -Dext.properties.dir=file:/C:\Users\Admin\Desktop\
The following error pring in logs: Properties location
Properties location
[${ext.properties.dir:classpath:}/properties.properties] not resolvable:
class path resource [properties.properties] cannot be opened because it
does not exist
How can I fix this error?
I saw that you are using spring boot application, according to the spring documentation you can try to use this environment property:
--spring.config.location=file:/path/location/file-name.properties
The final instruction would be:
java -jar import-0.0.1-SNAPSHOT.jar --spring.config.location=file:C:\Users\Admin\Desktop\import.properties
Spring Boot looks for application.properties on classpath. You don't need an explicit #PropertySource annotation. And #PropertySource doesn't have the capability to resolve SPEL in the path, which should be evident from the error message you're getting.
Use src/main/resources/application.properties. When you want to use the external file, use spring.config.location like #juan-calvopina-m suggested in his answer.

Spring boot external configuration of property file

I have a spring boot application that I can package in a war that I want to deploy to different environments. To automate this deployment it'd be easier to have the configuration file externalized.
Currently everything works fine with a application.properties file in src/main/resources. Then I use ´mvn install´ to build a war deployable to tomcat.
But I would like to use a .yml file that does not need to be present on mvn install but that would be read from during deployment of the war and is in the same or a directory relative to my war.
24. externalized configuration shows where spring boot will look for files and 72.3 Change the location of external properties of an application gives more detail on how to configure this but I just do not understand how to translate this to my code.
My application class looks like this:
package be.ugent.lca;
Updated below
Do I need to add a #PropertySource to this file? How would I refer to a certain relative path?
I feel like it's probably documented in there as most spring boot documentation but I just don't understand how they mean me to do this.
EDIT
Not sure if this should be a separate issue but I think it's still related.
Upon setting the os variable the error of yaml file not found went away. Yet I still get the same error again as when I had no application .properties or .yml file.
Application now looks like this:
#Configuration
**#PropertySource("file:${application_home}/application.yml")**
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
The application_home OS variable
$ echo $application_home
C:\Masterproef\clones\la15-lca-web\rest-service\target
My application.yml file(part it complains about):
sherpa:
package:
base: be.ugent.lca
Error upon java -jar *.war
All variations upon:
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'sherpa.package.base' in string value "${sherpa.package.base}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:204)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:178)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:808)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1027)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
... 142 more
Using external properties files
The answer lies in the Spring Boot Docs, I'll try to break it down for you.
First of all, no you should not use #PropertySource when working with Yaml configuration, as mentioned here under the Yaml shortcomings :
YAML files can’t be loaded via the #PropertySource annotation. So in the case that you need to load values that way, you need to use a properties file.
So, how to load propery files? That is explained here Application Property Files
One is loaded for you: application.yml , place it in one of the directories as mentioned in the link above. This is great for your general configuration.
Now for your environment specific configuration (and stuff like passwords) you want to use external property files, how to do that is also explained in that section :
If you don’t like application.properties as the configuration file name you can switch to another by specifying a spring.config.name environment property. You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
So you use the spring.config.location environment property.
Imagine you have an external config file: application-external.yml in the conf/ dir under your home directory, just add it like this:
-Dspring.config.location=file:${home}/conf/application-external.yml as a startup parameter of your JVM.
If you have multiple files, just seperate them with a comma. Note that you can easily use external properties like this to overwrite properties, not just add them.
I would advice to test this by getting your application to work with just your internal application.yml file , and then overwrite a (test) property in your external properties file and log the value of it somewhere.
Bind Yaml properties to objects
When working with Yaml properties I usually load them with #ConfigurationProperties, which is great when working with for example lists or a more complex property structure. (Which is why you should use Yaml properties, for straightforward properties you are maybe better of using regular property files). Read this for more information: Type-Safe Configuration properties
Extra: loading these properties in IntelliJ, Maven and JUnit tests
Sometimes you want to load these properties in your maven builds or when performing tests. Or just for local development with your IDE
If you use IntelliJ for development you can easily add this by adding it to your Tomcat Run Configuration : "Run" -> "Edit Configurations" , select your run configuration under "Tomcat Server" , check the Server tab and add it under "VM Options".
To use external configuration files in your Maven build : configure the maven surefire plugin like this in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>-Dspring.config.location=file:${home}/conf/application-external.yml</argLine>
</configuration>
</plugin>
When running JUnit tests in IntelliJ:
Run → Edit Configurations
Defaults → JUnit
add VM Options -> -ea -Dspring.config.location=file:${home}/conf/application-external.yml
Yes, you need to use #PropertySource as shown below.
The important point here is that you need to provide the application_home property (or choose any other name) as OS environment variable or System property or you can pass as a command line argument while launching Spring boot. This property tells where the configuration file (.properties or .yaml) is exactly located (example: /usr/local/my_project/ etc..)
#Configuration
#PropertySource("file:${application_home}config.properties")//or specify yaml file
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
There is a very simple way to achieve this.
Inside your original application.properties file you can just specify the following line:
spring.config.import=file:Directory_To_The_File/Property_Name.properties
It will automatically sync all the properties from the external property file.
Now lets say that you have a situation where you need to get properties from multiple property files. In that case, you can mention the same line in the external property file which in turn will take the remaining properties from the second property file and so on.
Consider the following example.
application.properties:
spring.config.import=file:Resources/Custom1.properties
Custom1.properties:
server.port=8090
.
.
.
spring.config.import=file:Resources/Custom2.properties
One of the easiest way to use externalized property file using system environment variable is, in application.properties file you can use following syntax:
spring.datasource.url = ${OPENSHIFT_MYSQL_DB_HOST}:${OPENSHIFT_MYSQL_DB_PORT}/"nameofDB"
spring.datasource.username = ${OPENSHIFT_MYSQL_DB_USERNAME}
spring.datasource.password = ${OPENSHIFT_MYSQL_DB_PORT}
Now, declare above used environment variables,
export OPENSHIFT_MYSQL_DB_HOST="jdbc:mysql://localhost"
export OPENSHIFT_MYSQL_DB_PORT="3306"
export OPENSHIFT_MYSQL_DB_USERNAME="root"
export OPENSHIFT_MYSQL_DB_PASSWORD="123asd"
This way you can use different value for same variable in different environments.
Use below code in your boot class:
#PropertySource({"classpath:omnicell-health.properties"})
use below code in your controller:
#Autowired
private Environment env;

How to set logging.path for spring-boot apps?

spring-boot provides several logging.* settings that can be applied in application.properties, like:
logging.level.=DEBUG
logging.file=myfile.log
logging.path=d:/logs/
Problem: myfile.log is generated, BUT inside the classpath! Why isn't spring taking my absolute path into account?
The Spring Boot documentation states
By default, Spring Boot will only log to the console and will not
write log files. If you want to write log files in addition to the
console output you need to set a logging.file or logging.path property
(for example in your application.properties).
and then describes how the logging.file and logging.path properties work. You should only set one.
If logging.file is set, it will write to that specific file. The documentation states
Names can be an exact location or relative to the current directory.
So you're likely writing to your current directory, which happens to be the same as your classpath.
If you set logging.path, Spring Boot
Writes spring.log to the specified directory. Names can be an exact location or relative to the current directory.
Check that your current directory isn't your classpath, if you don't want them to mix, and adapt one of the logging.file and logging.path accordingly.
for Spring boot v2.3.4 and above for sure:
it is NOT logging.file=.... ,
it is logging.file.name=....
I don't know if this is still needed, but you can set the absolute path with following code according to your example
logging.path=D:\logs\logfile.txt
You can alter the filename and the path like this. If the folder doesn't exist it gets created. On Windows you have to work with \ as seperator, while on Linux and Mac you need / as seperator.
REMEMBER: You cannot have logging.file AND logging.path in your properties together. It is either .file OR .path ... in your case the path.
Tested 2 Minutes before posting
For spring-boot version 2.3.x and above:
logging:
level:
root: INFO
my.app: INFO
file:
path: './logs/${spring.application.name}'
name: ${logging.file.path}/my-app.log
logging.file.name :Log file name (for instance, myapp.log). Names can be an exact location or relative to the current directory.
logging.file.path: Location of the log file. For instance, /var/log.
Reference: Spring-Boot Core Properties
You can also have this configuration on your app.properties. Thats how it is working in one of my projects.
logging.path=../logs
logging.file=${logging.path}/fileName.log
So, you can have both properties and one refers to the other.
I have set logging.file=C:/usr/local/tomcat/logs/hib.log in the application.properties and the setting like below in class
private static final Logger logger = LogManager.getLogger(ChargeMasterController.class);
logger.info("Total time taken for is ---------------------------" + time + " ms");
Logs are getting printed fine in the path mentioned as logging.file.
Now I want to print my logs in 2 different files for 2 different classes(In same package), how can I set 2 logging.file in application.properties

How should I invoke a packaged spring project from another spring project?

I have two spring projects both using maven. The first is a client for some api and the second is a console program that, in part, utilises that client.
I have packaged up the client into a jar and referenced it in the pom for the console program.
I have managed to get this working, just about, but I am not very happy with the solution:
1) The first problem I ran into was that each of the context xml files were named "applicationContext.xml". Therefore, I couldn't work out any way to reference the context file in the client, without renaming it to something else e.g. clientContext.xml. This works but is there any other way to reference it explicitly?
2) The next issue was how to invoke the clientContext.xml from within the console program. To do this, I have added <import resource="osrdClientContext.xml"/> to the applicationContext.xml of the console program and this seems to allow it to correctly find all of the defined beans. I'm not sure if this is best practice though?
3) Within clientContext.xml, I need to reference a properties file and so have the line <context:property-placeholder location="classpath:api.properties" />. This works when running the client on its own but appears to get ignored (or fails to find the file) when running the console program. The api.properties file is in the root of the packaged jar for the client and the jar is in the classpath of the console program. The only workaround I have found is to manually copy the properties file into the console program, at which point it is found without any problem.
4) Both projects have a resources directory with sub-directories "dev", "beta" and "prod". This allows me to define different properties depending on the maven profile I want to run against. This works fine for the individual projects but when I package the client, it only includes the properties files for the profile I am running against (which makes sense). However, that then means if I run the console project against profile "beta", it will still run the client against whatever profile it was packaged against. It would be handy to be able to package all of the properties files and get the client to run in the same profile as whatever is depending on it. Is that possible/a good idea?
Ad 1: The common place to put your JAR-based XML contexts is inside META-INF/your/project/name folder. You can check for example spring-batch-admin project. Also nowdays it is more common to name the context files {name}-context.xml (e.g. central-context.xml).
By following the advice above, you should not have problems with name conflicts. However it should be possible to overcome such problem by using classpath* pseudo protocol in your import definition:
<import resource="classpath*:do/not/put/in/root/this-can-be-duplicate.xml"/>
Ad 2: This is completely legit. You can see the same practice in the Spring Batch Admin example as linked above. Just add the classpath: or classpath*: to the resource path.
Ad 3: That is very strange and I have no clue to what is going on there.
Ad 4: This is possible to achieve via Spring profiles (not Maven profiles):
<beans profile="dev">
<context:property-placeholder location="classpath:META-INF/dev/my.properties"/>
</beans>
or via new SpEL support:
<context:property-placeholder location="classpath:META-INF/#{systemProperties['my.jvm.property']}/my.properties"/>
However what I like is to have a default properties and then let the main application be able to override them. This means, that your configuration will be on a single place and not inside the JAR. You can achieve this via properties hierarchy:
<context:property-placeholder location="classpath:META-INF/my-default.properties,classpath*:META-INF/my-optional-overrides.properties"/>
UPDATE just discovered that <context:property-placeholder> has problems with SPeL. However you can still use SPeL (and even other property configurers) when defining the PropertyPlaceholderConfigurer manually (i.e. via <bean>).

Categories

Resources