How can I make a profile-specific bootstrap.yml? - java

I want to have different property values in a bootstrap.yml file depending on a spring profile passed to a starting application (the same way as it works for application-{profile-name}.yml).
How is it possible?

According to the documentation it should work pretty much the same.
Changing the Location of Bootstrap Properties:
If there is an active profile (from spring.profiles.active or through the Environment API in the context you are building), properties in that profile get loaded as well, the same as in a regular Spring Boot app — for example, from bootstrap-development.properties for a development profile.
That is it should be possible to suffix the bootstrap yaml with the environment name to make it take effect.

Related

How can I externalize some config variables in spring boot?

I have a yaml file that contains some credentials for azure keyvault. This project is I am working on is a shared git repo so I would like to set these values as environment variables for the whole project not just for myself
application.yml:
azure:
keyvault:
uri:someUri
client-id:someClientId
client-key:someClientKey
but I want to have them set up like this:
azure:
keyvault:
uri: ${uri}
client-id:${clientId}
client-key:${clientKey}
Is there a way to set those values and have this work for others without them having to manually set these values in their environment?
You can ignore the .yaml in gitignore so you can use your config in your environment. And if you pull from others their config won't overwrite your config.
If you want if like dynamically
java -jar myapp.jar --spring.application.json='{"foo":"bar"}'
You can add variables like this in start command. Configure in your Run configuration.
The syntax you've presented above is supposed to work.
I usually use capital letters for 'convention' but other than that its fine.
However providing such a syntax effectively means that you don't want to define property values in your application so you'll have to get them from elsewhere.
From your question I understand is that your primary concern is your teammates and in your setup each one of your peers has clientId, key, etc.
In this case you can create a script that will "export" all the variables to be environment variables automatically, they'll run it only one time and it will work since than.
Another option which is kind of similar is providing a property SPRING_APPLICATION_JSON that will refer to the json with a configuration, spring boot application can read it as written in the official documentation

Where to define properties in SpringBoot which are common across all environments?

I have few properties common to all environments (Ex. spring.jpa.properties.hibernate.ejb.interceptor) which I have kept in application.properties under resource directory.
I have DB properties defined in environment based properties file which I pass externally through command line while starting the app:
java -jar -Dspring.config.location=<path-to-file> mySpringBootProject.jar
However, spring.jpa.properties.hibernate.ejb.interceptor is not being set when I am passing properties file externally.
Do I need to define common properties even in external file?
Or is there a way I can define them in a single place which is reused when not overridden?
You can use multiple profiles to do this. For example, create property files:
application-dev.properties
application-prod.properties
application.properties
Place your environment-specific properties in the application-${env}.properties file and your common properties in application.properties.
There are multiple ways to tell spring which profiles to use, for example the --spring.profiles.active flag.
See the Spring Boot documentation for more details about the property file search order.
application.properties will normally be overridden by Boot projects. Instead, you can add a properties file in a non-conflicting location (such as src/main/resources/my/package/foo.properties) and use #PropertySource on your autoconfiguration file to add it.
Properties is a file extension for files mainly used in Java related technologies to store the configurable parameters of an application. The advantage of using properties file is, we can configure things which are environment specific (or are prone to change over a period of time) without the need of changing anything in code. Hence inheriting common properties is not a good approach. If a property seems to be static for all e.g. environments, then it shouldn't be a property.
But, it could be we have multiple development environments and production, where we would share same properties in the environments meant for development purposes and different properties for production. In this case we could create a common properties file and inherit it in all our environment specific properties files. Another scenario could be, that at the moment of development the property is same for all environments, but we would like to provide the option of changing it in the future, when required.

Setting an active profile in bootstrap.yml does not affect evaluation of application.yml. Is this a bug, or a feature I don't recognise?

When I add spring.profiles.active=DEV in bootstrap.yml this is processed fine for bootstrap. I.e. the DEV profile will be loaded from the bootstrap properties. However it doesn't work when processing application.yml.
From stepping through the code, this seems to be due to the information about the activated profile is not pushed far enough up (only into the StandardEnvironment, which seems to be local to the ConfigFileApplicationListener. When evaluating the application.yml the environment is created from the original information again and the profile is not read.
Unfortunately I wasn't able to find any documentation on that. Documentation always refers to setting this property in the application.properties. Now I'm curious if this is an (intended) part of the feature that might need some documentation brush up, or rather a bug that should be fixed?
When combine use with spring cloud, you can set an active profile in bootstrap.yml.
Add this to you pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-context</artifactId>
<version>1.2.4.RELEASE</version>
</dependency>
Just for reference, it seems that this was triggered by a bug.
At least with Spring boot 2.0.3 it is possible to define active profiles within bootstrap.yml and activate profiles that are defined in application.yml
Ensure not to have double quotes around your active profiles within the yml configuration, otherwise they are not treated correctly.

spring profile groups

I have an application, for which I can specify the profiles I want to run it on.
but I also want to group these profiles into things like credentails, application performance, memory-print, application behaviour etc.
Ex. I can run the following profiles
-Dspring.profiles.active=production,cached-local,db-connection-pooled...
but I would prefer initializing it as
-Dspring.profiles.active=production,super-fast
#the above activates method level caches, db connection pooling etc
#super-fast triggered activation of cached-local, db-connection-pooled profiles
or
-Dspring.profiles.active=dev,low-footprint
#the above dosent enable caching, or db connection pooling
can this be achieved without writing any custom code like
How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property.
I am fine even if I can load these from properties files or inside spring-xml config.
I am using xml only config on spring 3.1.
Spring Boot have since added functionality to address this problem, called "Profile Groups". A profile group allows you to define a logical name for a related group of profiles.
For example, we can create a production group that consists of our proddb and prodmq profiles.
This allows for a grouping to be defined, which is added to the spring-profiles-active, which when enabled, in turn, enables other profiles.
For more information see https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.profiles.groups
I don't know of any way to achieve this without custom code which would manipulate the active profiles in a ConfigurableEnvironment.
We're trying to achieve the same indirection pattern as rights vs. roles (group of rights) in a security framework, but since this doesn't come out of the box, I ended up having to work around it.
I kept my profiles general, e.g. production and super-fast in your case, and for each bean that is sensitive to those profiles, I set the correct #Profile. To make refactoring easier, I used two techniques.
Create a meta-annotation for each profile, e.g. #Production, #SuperFast and make the profile name a public constant, e.g. Production.PROFILE_NAME = "production".
When marking the profile of any bean, use your new meta-annotation if it only applies to one profile, or use #Profile({Production.PROFILE_NAME, ...}) if it applies to multiple profiles. You have to do this because you can't apply two profile meta-annotations to the same bean, at least not until 4.0.
For example,
#Profile(Production.PROFILE_NAME)
public #interface Production {
public static String PROFILE_NAME = "production";
}
The point of all this is that you can now use your IDE to look for usages of #Production or Production.PROFILE_NAME if you need to quickly understand or change what beans are being pulled in.

Pass properties to log4j before it loads

Is there a way to pass data or setting to log4j before it loads and then use that property within the config file.
I was assuming there is a system properties I could use:
log4j.appender.R.File=/usr/local/pfs/logs/${ws.host}/log4j.log
Where ws.host is the property I want to use.
But how can I set that value?
Also, I am in a web environment. How can I know at what point to set the property setting before log4j loads.
The default log4j PropertiesConfigurator supports variable substitution.
http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PropertyConfigurator.html
So, you could pass system properties like this "-DmyProject.logFile="/temp/test.log" to your Java startup, and then in the properties files have "log4j.appender.R.File=${myProject.logFile}".
If working from a web environment, you might want to check out Spring's Log4jConfigListener. It uses a listener (Servlet API 2.4+) to initialization log4j ahead of other components. Even if not using Spring, you should be able to use the source as an example to easily create your own listener.

Categories

Resources