External application.properties file overriding values in Spring Boot 2.2.1 - spring-boot

I have seen many questions in regards to Spring Boot external configuration, in specific, externalizing a application.properties file, but didn't find a specific answer on whether property values from externalized application.properties files should be merged or the whole .properties file on the classpath should be overridden with the external one.
After recent app upgrade to Spring Boot 2.2.1-RELEASE version, there was a need to enable bean overriding with spring.main.allow-bean-definition-overriding=true property, which is set in the application.properties file on the classpath. Since we want to use an external application.properties file, I created one(same name) without the aforementioned property and loaded it with the following property in IntelliJ:
java -jar appName.jar --spring.config.location="C:\Users\User\Downloads\application.properties"
The error came up as though the external props file completely overrode the classpath file, without looking for the mentioned property in the classpath file and using the missing property from the classpath application.properties:
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'userRepository' could not be registered. A bean with that name has already been defined and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
After adding the bean overriding property to the external application.properties file, but removing it from the classpath one, error is gone.
In Spring docs, it is clearly stated that :
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:
...
Application properties outside of your packaged jar (application.properties and YAML variants).
Application properties packaged inside your jar (application.properties and YAML variants).
After testing it out with IntelliJ and a packaged jar, both method exhibit the same: seems like the whole file is being overridden and values are not merged, but only loaded from the externalized properties file. My questions is, is this the expected behavior or am I missing out on something ?
EDIT: tested the behavior with jar

Related

is there a way to set default value of spring configuration property when some dependency/jar resp. it's classes are available in classpath?

example:
I have groupId=myGroup, artifactId=feignOkHttp dependency jar file.
In case I want to do some standard auto-configuration there, I would create auto-configuration classes and refer it in META-INF/spring.factories
However, here I need to set configuration property value usually placed in application.properties/.yml
feign.okhttp.enabled=true
the property is used in spring's or 3rd-party artifact's auto-configuration classes.
Is it somehow possible or do I need to set it in application.properties/.yml file in each project where I will include my dependency?

Spring Cloud Config: Bootstrap context not loading profile-specific property files for binding

Setup
Spring Boot 2.6.0
Spring Cloud Config 3.1 RC1
Apache Maven 3.8.x
OpenJDK 11
Overview
I have a multi-module Apache Maven project that is set up with the following modules:
bootstrap: contains a PropertySourceLocator for BootstrapConfiguration, defined in spring.factories file.
starter: depends on bootstrap, and it's a (servlet-based) web application
reference: deploys the starter application using the Maven Cargo plugin, deploying into an Apache Tomcat 9.0.55
Runtime
The starter module declares a configuration class, annotated with #PropertySource("wa.properties"). This wa.properties on the classpath of the starter module has a setting: cas.authn.syncope.name=Starter
The starter module has a ServletInitializer that sets the spring.config.name property to "wa" when building the spring application.
The reference module only has a wa-embedded.properties file on the classpath with a setting: cas.authn.syncope.name=Embedded
The reference module starts with the spring activated profiles: embedded,all
Note: the cas.authn.syncope.name is bound to a Java POJO, CasConfigurationProperties, that is annotated with #ConfigurationProperties("cas").
Observation
The following bean in the application exists, simplified for this post:
#Bean
#ConditionalOnMissingBean(name = "something")
#RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public Something something(ApplicationContext ctx, CasConfigurationProperties cas) {
...
}
If I look at the contents of cas.getAuthn().getSyncope().getName()), it shows: "Starter"
If I look at ctx.getEnvironment().getProperty("cas.authn.syncope.name"), it shows "Embedded".
In other words, property binding used during the bootstrapping process does not match the actual environment for the application's context.
Analysis
It appears that when the bootstrap application context is created, wa-embedded.properties, a profile-specific property is not read. In fact, the only property source that is used for binding is wa.properties as part of "localProperties", which I believe comes from #PropertySource("wa.properties"). Nothing else is read or found.
Then, property binding takes place binding CasConfigurationProperties and cas.authn.syncope.name initialized from #PropertySource("wa.properties"). The value of this property is set to Starter.
Then, the application servlet context is initialized and its environment is post-processed with profiles and the appropriate listener and Spring beans are created. In particular, this bean:
#Bean
#ConditionalOnMissingBean(name = "something")
#RefreshScope(proxyMode = ScopedProxyMode.DEFAULT)
public Something something(ApplicationContext ctx, CasConfigurationProperties cas) {
...
}
...shows that ctx is the actual application context with an environment that is post-processed via all profiles and shows ctx.getEnvironment().getProperty("cas.authn.syncope.name") as "Embedded".
However, CasConfigurationProperties was processed using the Bootstrap context only, and its equivalent property shows "Starter".
...which means the bean would be created using the wrong values in CasConfigurationProperties.
Research
This setup works OK using Spring Boot 2.5.6 and Spring Cloud 3.0.5. I don't think anything in Spring Boot has changed that would affect this, but I do see a number of differences in Cloud between 3.0 and 3.1.
I am not sure I can create a reproducer to adequately showcase this. I'll try. In the meantime, could you evaluate this and see if this might be seen as a bug, or misconfiguration of some kind?

Externalizing values inside application.properties (ex. server.port, spring.datasource.url, and etc.)

server.port = ?
spring.datasource.url = ?
spring.datasource.username = ?
spring.datasource.password = ?
I want to externalize all the "?" values outside the application.properties, and have them in a text file or something.
I already have a configuration.txt file which holds other values, used in the services, but I just don't know how it works for the application.properties.
Solved, just have the property file in the same path where the jar file is, then spring boot will replace the values for you.
Spring.io Externalized Configuration
Spring Boot uses a very particular PropertySource order that is designed to allow sensible overriding of values. Properties are considered in the following order:
Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
#TestPropertySource annotations on your tests.
properties attribute on your tests. Available on #SpringBootTest and the test annotations for testing a particular slice of your application.
Command line arguments.
Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
ServletConfig init parameters.
ServletContext init parameters.
JNDI attributes from java:comp/env.
Java System properties (System.getProperties()).
OS environment variables.
A RandomValuePropertySource that has properties only in random.*.
Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
Application properties outside of your packaged jar (application.properties and YAML variants).
Application properties packaged inside your jar (application.properties and YAML variants).
What this means is that what you want to do is supported without needing to do anything fancy inside your application.properties file.
Spring Boot will look at the application.properties file outside of your jar and consider any values in there and use them instead of any values in the application.properties file inside of your jar.
So, wherever your jar is, put the application.properties file you want for that environment. See the link for more details on just how much you can customize this (profiles, YAML, system properties, environment variables, etc.)
You might also consider moving to a Spring Cloud Config implementation, but that's a bit more work.

Spring Cloud Config Client - Java Configuration HashMap or properties

Im newbie in MicroServicies, euereka and spring...
I want to start my Eureka client, getting the values from a HashMap that I created before starting the application in which the cloud information is.
HashMap config = new HashMap ();
config.put ("spring_cloud_config_enabled", "true");
config.put ("spring_application_name", "MicroService");
config.put ("spring_profiles_active", "default");
config.put ("spring_cloud_config_uri", "http://myHost:8888");
If it were empty, access the bootstrap.properties information.
Does anyone know how could i do it?
Thank you!
Following is the order of loading properties in spring application:
Bootstrap.properties/yaml
Local application.properties/yaml
Command Line Over-rides
Cloud Config application/profile based properties
Load/Over-ride happens in above format as observed. Hence you can decide fallback logic based on your requirement.
Externalized loading is summarized at following link
Adding extract from there
Devtools global settings properties on your home directory (~/.spring-boot-devtools.properties when devtools is active).
#TestPropertySource annotations on your tests.
#SpringBootTest#properties annotation attribute on your tests.
Command line arguments.
Properties from SPRING_APPLICATION_JSON (inline JSON embedded in an environment variable or system property).
ServletConfig init parameters.
ServletContext init parameters.
JNDI attributes from java:comp/env.
Java System properties (System.getProperties()).
OS environment variables.
A RandomValuePropertySource that has properties only in random.*.
Profile-specific application properties outside of your packaged jar (application-{profile}.properties and YAML variants).
Profile-specific application properties packaged inside your jar (application-{profile}.properties and YAML variants).
Application properties outside of your packaged jar (application.properties and YAML variants).
Application properties packaged inside your jar (application.properties and YAML variants).
#PropertySource annotations on your #Configuration classes.
Default properties (specified by setting SpringApplication.setDefaultProperties).

spring.config.location not working without classpath resource

I have my config class as below
#Configuration
#PropertySource(value= "classpath:conf/agent.properties")
public class AppConfig{
While running the application using
java -jar app.jar spring.config.location=path-to-external-property-file
the application runs fine and takes the properties from the external properties file, but if the properties file in classpath is missing FileNotFoundException is thrown, is this expected behavior? For me it should work with the external properties, it should not care about classpath resource and stop running.
To overcome this I am currently using ignoreResourceNotFound = true
You seem to mis-understand the meaning of spring-config-location.
From the docs, by default spring searches for a file named application.properties in certain locations in your project(/config, ..) to setup application context.
You can tell spring that you don't want to use this packaged file in the project, and you will specify the file needed to setup application context at run time using command line arguments. This is facilitated using
spring-config-location option.
Having said that, in your project you might have several configuration (#Configuration) files. And some files need some properties to be loaded from some file. This can be specified using #PropertySource, which is what you are doing. This is not like a replacement for application.properties. #PropertySource is just an indication to tell spring that it needs to read a file to inject properties specified in a particular class.
Hence even if you specify external config location spring before setting up the AppConfig class it looks for the Source mentioned in #PropertySource

Resources