How to access environment variable externally in spring boot? - spring-boot

Is it possible to access environment variable of different application.properties from a single place. Actually we are building this software where we have different application.properties for different projects like user-asset. So is it possible to have all environment variable at one external place. If yes, how will it be accessed?

You would have an application.properties file that defines variables that would never change in what every situation you have.
application.properties
server.error.whitelabel.enabled=true #Just an example
Then you could have a separate application.properties with a different name such as application-active.properties. This file would add onto the base application.properties file.
application-active.properties
example.enviroment.variable=${I_AM_AN_ENVIROMENT_VARIABLE}
Then you could have a different application.properties file that has the same property name, in this case example.enviroment.variable.
application-dev.properties
example.enviroment.variable=${I_AM_A_DIFFERENT_ENVIRONMENT_VARIABLE}
Then in your code, you would just need to grab the example.enviroment.variable property depending on the current profile and it would grab the correct environment variable.
To specify what application.properites look at using profiles in spring-boot.

If its an environment variable, then I think multiple applications can access the same variable.
But if its inside the application.properties file, then I think its not possible.
Not only that, if you really feel that one application needs to access the application.properties of another, then I believe this is not a right way to proceed.
Rather, you should externalize the configurations (maybe by using a config server like spring-cloud-config) and share the common properties between the applications.

Related

Any way to split Spring Boot configuration into multiple properties files without having to specify an environment variable/system property

New to Spring Boot here, long-time Spring Framework user though.
I'm looking for a way to split my externalised configuration into multiple .properties files, for better readability and manageability.
I already saw this SO answer: having the ability to specify a list of configuration file names in spring.config.name (which, by the way, doesn't seem to be mentioned in Boot reference documentation, correct me if I'm wrong) would solve my problem perfectly, however that configuration property can be specified only via system properties or environment variables. If I try to specify it inside my application.properties file, it gets ignored. The same happens for spring.config.additional-location. I understand this happens because, when application.properties is read, it's too late to tell Spring Boot to search for different externalised configuration file names. However this is not a proper solution, because the way I split my configuration should be an "implementation detail" that the consumer of my application shouldn't be aware of, so I don't expect the consumer to specify an external parameter otherwise my application breaks out-of-the-box.
I think that a way to do this should be provided. Perhaps some import mechanism for .properties files or the ability to specify spring.config.name even in application.properties (some known and reasonable limitations would be acceptable).
The best I could find out is to use #PropertySource, but this is not profile aware: unless you use some ugly nested class hack, or you put spring.profiles.active variable in the resource name (which will break if multiple profiles have been activated), you won't get the benefit you have for application.properties profile-specific files.
I was not able to find an "official way" to do this, apart from some statements from Spring Boot devs that say that they're rather promoting the use of a single (possibly giant...) externalised configuration file. It seems like this position is not so popular, judging from the post reactions on GitHub, and IMHO it really seems to be a basic feature missing. I have been working with multiple properties files in Spring Framework (using XML configuration) for years and I never felt that having an only huge file would have been better.
If I understand it right, in Boot 1.x this was in some way possible using the location attribute of #ConfigurationProperties, which is however missing in Boot 2.x.
Any suggestion?
Have you tried with Spring Profile?
What you can do is create application-file1.properties/yml, application-file2.properties/yml and put it in config location and then add spring.profile.active=<your env profiles>,file1,file2.
It will load the files.
This profile entry can be in bootstrap.yml, or JVM args to application, in Manifest-<env>.yml in case of Pivotal Cloud Foundry. Not sure on AWS and other cloud provider.
Hope this will help.

How does Spring map Docker environment variables?

So I found this sample project. In docker-compose.yml I notice that he is supplying a environment variable called REGISTRY_HOST, and that this is then used in various application.yml files in the project, here for instance.
What I am wondering is, how does this mapping work and is it Docker or Spring that performs the magic? For instance, he is binding registry.host and registry.port, but how exactly is this mapped? How come it is registry that is the prefix, and where does registry.host come from when it isn't in the compose file?
Basically what docker does is it just assigns the environment variable, nothing more. But on Spring side, it reads this variables and tries to assign to an application property. Which is explained in Externalized Configuration Please see the 24.7.2 Relaxed Binding part of the documentation.

How to override profile-specific properties with a different profile?

I currently have the following config setup in spring boot:
application.properties
app.database.host=${DB_HOST}
app.database.port=${DB_PORT}
app.database.name=${DB_NAME}
app.database.user=${DB_USER}
app.database.password=${DB_PASSWORD}
app.database.schema=${DB_SCHEMA:public}
spring.datasource.url=jdbc:postgresql://${app.database.host}:${app.database.port}/${app.database.name}
spring.datasource.username=${app.database.user}
spring.datasource.password=${app.database.password}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
application-local-dev.properties:
app.database.host=${DB_HOST:localhost}
app.database.port=${DB_PORT:5432}
app.database.name=${DB_NAME:db_name}
app.database.user=${DB_USER:root}
app.database.password=${DB_PASSWORD:root}
app.database.schema=${DB_SCHEMA:public}
application-load-fixtures.properties:
spring.profiles.include=local-dev
spring.profiles.active=load-fixtures,local-dev
app.database.name=${DB_NAME:db_name}_fixtures
The idea here is that when starting the app in default mode, it will fail to boot when critical properties like database name are missing.
They should be passed via environment variables.
For development purposes, this is unnecessary overhead when setting up the project because we have a docker container with static credentials and I'd like to provide them as defaults. Therefore, I created a profile local-dev that will use default values to be able to connect to our docker database and still have the ability to override them via environment variables in case someone needs to.
Until here, everything works fine.
But now, we also have a profile that is used to load fixtures into the database (drop all tables, recreate and fill them with data).
For obvious reasons, I want to ensure that this cannot be done on an arbitrary database, so I created a profile load-fixtures that should inherit all properties from local-dev and override the database name. However, this approach seems to be wrong. I can see in the spring log that the profiles are loaded properly:
2017-11-16 13:32:11.508 INFO 23943 --- [ main] Main:
The following profiles are active: load-fixtures,local-dev
But it still uses the database name provided by the local-dev profile.
When I remove the line
app.database.name=${DB_NAME:db_name}
from the local-dev config file, it works.
However, what I want to avoid is having to add new properties to both, local-dev and load-fixtures, whenever we add a new configuration property to the project.
I understand that profile specific properties take precedence over non-profile specific ones. And also that non-default location properties take precedence over properties from the default locations. But here, both profiles (local-dev and load-fixtures) are in the same location, and they are also both profile specific.
What are proper ways to go about this problem?
Thanks in advance!
I recently came across quite the same problem and had to figure out which precedence Spring applies to several profile specific property files. Unfortunately this is not well documented and I did not find the location of the code that is responsible for that.
However after some tests and tries I'm pretty sure it works like this (or at least in a similar way):
Probably some kind of map is used to gather up all properties of all the different places and possibilites where you could define them like documented here. So for example a property my.value is defined in application.properties and so stored in the mentioned map. Then the same property is found as Java system property. Since this way of defining a property is higher in the PropertySource-order it will override the value found before in the map. Until here it is clear according to the documentation that the Java system property will win.
But as we come to two different sources on the same precedence level like two different profile specific property files the documentation is not a 100% clear in my opinion. However it says in 24.4:
If several profiles are specified, a last-wins strategy applies. For example, profiles specified by the spring.profiles.active property are added after those configured through the SpringApplication API and therefore take precedence.
Maybe it is just the example that is not optimal here or I just do not understand it correctly. But I guess the "last-wins" strategy also applies to all profiles defined for example in spring.profiles.active. That means if you run java -jar -Dspring.profiles.active=dev,fix application.jar, the properties in application-fix.properties will overwrite the values of properties having the same key in application-dev.properties.
So in your case considering the output of your application I guess you specified something like java -jar -Dspring.profiles.active=load-fixtures,local-dev application.jar. If I was correct, you would just have to change that into java -jar -Dspring.profiles.active=local-dev,load-fixtures application.jar.

Environment specific properties from user home in springboot

I am working on a spring boot application in which i have to set Environment specific properties from user home folder.
i dig Google for the same & found we can put different properties file (dev, test, production) under resources and then we have to tell spring boot which environment we want to use using spring.profiles.active=dev OR prod.
however, my requirement is quite different. i will put a file in user home in my system & want to read properties form that file. how can i do that, need guidance.
Helping hands will be highly appreciated.
From the Spring Boot docs:
You can also refer to an explicit location using the spring.config.location environment property (comma-separated list of directory locations, or file paths).
As the docs go on to state, this must be specified on the command line or as an environment variable.
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
We explain that use case in a Devoxx presentation using EnvironmentPostProcessor, please refer to this section of the presentation for more details. You can also find the code sample online.
Well, it seems in your case you dont need environment variable. For production server your property file will be staying in and in staging machine it is also staying at same place. So where ever you deploy it will pick from . IMO you don't need to set environment, you just have to point property file to
Now to define this path you have 2 ways..
- You can put static path in your code
- You can set environment variable like Property_Path and read it in spring boot application..
However If you want to go one step ahead, you can use spring cloud configuration manager, by passing application+profile name to it, CM can fetch property file from directly from git or file system for you ...

How can I directly add properties from a Spring Boot property source to the environment

I have a Spring Boot property source file containing a set of arbitrary properties. I would like to get all of those properties and add them to the environment.
I tried injecting the Environment into the class, and I am able to use that to get known properties. But I am not sure how to get all properties from there.'
If course I can use a traditional Properties.load() but is there a Spring way to do that?
Have you tried #PropertySource anotation?
I wouldn't recommend using PropertySource because you can't configure the precedence of the properties that you add. You may want that these properties can be overridden in some way, maybe? Or you may want that these properties take precedence over others. For this, I recommend you implement an EnvironmentPostProcessor.
There is a sample in this university session at Devoxx where we showcase how to read a file from the home directory and add it after command line properties. You could do pretty much the same thing and order them the way you want.
The sample app is available here if you want to give that a try.
If you put your properties into the "application.properties" (or any of the other places described here), the properties are automatically available in Spring's Environment.
One way to access the properties then is simply to #Autowire the Environment into the class where you want to access it.

Resources