Setting variable value based on spring profile - spring

How to assign value to variable based on region?
Lets says
system properties,
dev-url="dev-abc.com",
prod-url="prod-abc.com" and
qa-url="qa-abc.com"
#Value( #{systemProperties. ??? )
String url;

if you have all properties inside on property file you can use :
#Value("${spring.profiles.active}-url") String url;

I would suggest to avoid profiles as much as possible. Modern applications should strive to follow rule 3 of 12 Factor app:
The twelve-factor app stores config in environment variables
With Spring Boot you would have environment variable URL environment variable and use it in Spring Boot as ${URL}. Each environment would have this environment variable configured to correct value.

Related

Override Spring Boot yaml property via environment variable

Using Spring Boot 2.6.1, If I have an application.properties file that looks like:
spring.datasource.url="jdbc://blahblah"
I can override that value at runtime with an environment variable named spring.datasource.url and my application will connect to the database specified in the env var.
However, if I have an equivalent application.yaml file, specifying the environment variable that way appears to have no effect.
spring:
datasource:
url: "jdbc://localhost..."
However, if I rename my environment variable to SPRING_DATASOURCE_URL, the override works again. This appears to be consistent across other properties as well (not just the datasource url).
Looking through the docs it wasn't obvious why this should be the case, except that yaml configuration seems like it's generally treated a little different than "normal" properties files.
Is this behaviour expected?
As described in the documentation, you should use the environment variable SPRING_DATASOURCE_URL to set the spring.datasource.url property. I am surprised that spring.datasource.url worked at all when configured as an environment variable and I would not rely on it continuing to do so.

Set a property value in spring from a static field

I have a situation where I need a property value (application.name) before the application context is loaded - spring boot, before SpringApplication.run is called, and during context loading.
In my ApplicationMain class which calls SpringApplication.run, I have a constant public static final NAME = "MyApplicationName".
My issue is that we have some libraries that are injecting the value via #Value("${application.name}").
Is there a way set the application.name property in the context from this constant value?
I was thinking I could do a post-construct and then set it in the environment - similar to the solution described here, but that doesn't guarantee that it will be available for all injections by #Value.
I was hoping there was a similar mechanism to #Bean on a method which could set the value for the property, but I don't see one anywhere.
Variables can be injected on Spring Boot in several ways, but for me one of the best way is using operating system variables in *nix or Windows you can define variables like this:
Windows
SET APPLICATION_NAME = "MY APP"
*nix
export APPLICATION_NAME = "MY APP"
Be warned that the underline character (_) is replaced by . inside your application. Other way is using Java properties defined using -Dapplication.name="MY APP", that goes in your application command line. After you defined that variables in the operating system you can catch them in your code using:
#Value("${application.name}")
So, again, I recommend you using environmental variables to store your application configuration, so the operators or devops people will be able to change your application behavior without touch code or internal properties files (inside your application package).
Also another way is setting System properties (System.setProperty), that will make Java applications receive variables set in run-time. Actually is the same map (System map) used using -D in command line, however it is done in run-time instead of in command line. An example:
System.setProperty("application.name","MY APP");

What is advantage of using #value annotation in Spring Boot

I am new to Spring Boot and I am doing code cleanup for my old Spring Boot application.
Below code is using #Value annotation to inject filed value from properties file.
#Value("${abc.local.configs.filepath}")
private String LOCAL_ABC_CONFIGS_XML_FILEPATH;
My doubt is instead of getting value from properties file, can we not directly hardcode the value in same java class variable?
Example: private String LOCAL_ABC_CONFIGS_XML_FILEPATH="/abc/config/abc.txt"
It would be easier for me to modify the values in future as it will be in same class.
What is advantage of reading from properties file, does it make the code decoupled ?
This technique is called as externalising configurations. You are absolutely right that you can have your constants defined in the very same class files. But, sometimes, your configurations are volatile or may change with respect to the environment being deployed to.
For Example:
Scene 1:
I have a variables for DB connection details which will change with the environment. Remember, you will create a build out of your application and deploy it first to Dev, then take same build to stage and finally to the production.
Having your configurations defined externally, helps you to pre-define them at environment level and have same build being deployed everywhere.
Scene 2:
You have already generated a build and deployed and found something was incorrect with the constants. Having those configurations externalised gives you a liberty to just override it on environment level and change without rebuilding your application.
To understand more about externalising techniques read: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html
Here #value is used for reading the values from properties file (it could be a any environment like dev, qa, prod) but we are writing #value on multiple fields it is not recomonded so thats instead of #value we can use #configurableProperties(prefix="somevalue>) and read the property values suppose `
#configurableProperties(prefix="somevalue")
class Foo{
string name;
string address;
}
application.properties:
somevalue.name="your name"
somevalue.address="your address"
`

spring boot YAML default and environment variable override like HOCON files

Is there a way in spring-boot YAML file to do the same as in HOCON files where you can have a default and be able to override it with an environment variable like this:
basedir = "/whatever/whatever"
basedir = ${?FORCED_BASEDIR}
In this case in HOCON if you don't define a environment variable named FORCED_BASEDIR then basedir will be "/whatever/whatever" but if you do then the value of basedir will be whatever is defined in the environment variable.
Thanks
So based on webdizz answer below I looked up a little bit and I found a pretty good description in book "Spring Boot in Action". Here is the hierarchy:
There are, in fact, several ways to set properties for a Spring Boot application. Spring
Boot will draw properties from several property sources, including the following:
Command-line arguments
JNDI attributes from java:comp/env
JVM system properties
Operating system environment variables
Randomly generated values for properties prefixed with random.* (referenced
when setting other properties, such as `${random.long})
An application.properties or application.yml file outside of the application
Licensed to Thomas Snead 58 CHAPTER 3 Customizing configuration
An application.properties or application.yml file packaged inside of the
application
Property sources specified by #PropertySource
Default properties
Spring Boot provides means to define variables at many levels and your case is supported, you just need to define variable in following way:
in application.yml:
basedir: "/whatever/whatever"
and in environment:
export BASEDIR = "/another/whatever"
Then in runtime application will use value from environment.
For more details check this out enter link description here.

Spring boot - expose common application properties with different names

I have a requirement where I need my custom application properties to act as aliases to various common application properties that spring provides for different packages.
Example:
Whenever I set a value to the application property foo.host, it should set the value for spring.rabbit.host property.
Similarly setting the value for foo.port should set the value for spring.rabbitmq.port.
Can this be achieved?
It can, you can add these to your application.properties:
spring.rabbit.host=${foo.host}
spring.rabbit.port=${foo.port}
However, if you still provide spring.rabbit.host via system properties, as an environment variable or as direct argument then it will take precedence over foo config.

Resources