Manually force reading environment spring property - spring

If we can use spring context in order to read properties which where already loaded from a property file, like this:
ctx.getEnvironment().getProperty("viva.val")
How can I get the above line getting an updated value once I manually cahnge the property file?
I have notice that the getEnvironment().getProperty(...) remember the old value, but I somehow wants to manually set a new value for the property, so the next time it gets called, it will be the new value, or even better, telling the context to read the property file again.
Is there any way to do that (Note, I'm not using singletone for the above code, and also not using #Value) without restart or spring cloud config.

Related

Mule Expression component not able to fetch value from properties file

I want to fetch values dynamically from properties so I have implemented one poc. In that poc I have declared one object with value in mule expression component. After that I am fetching the value key from properties file. It is showing exceptions while testing the application.
Exception MSG: Root Exception stack trace: unresolvable property or identifier: $
EX-1:
flowVars.deptCode=21432143;
property3=${flowVars.deptCode};
EX-2:
property3=${21432143};
In the above two examples ex-2 has worked fine and ex-1 has failed .
Please let me know if anyone have clarity on that.
Thanks,
Praveen
Mule is using Spring Properties which can be kept in a seperate properties file and then retrieved/used in your application via ${propertyName}.
A property placeholder is used to define where you keep those properties.
Ex 1 is not possible because properties are not aware at all of any variables or properties inside of your Mule application.
Another issue is that those files will be loaded when the application is started.
If you change the value of a property a restart of your application is needed, so your approach isn't going to work.
More info in the docs here:
https://docs.mulesoft.com/mule-user-guide/v/3.8/configuring-properties
You can use dataweave script to dynamically read values from property file
#[dw("p(flowVars.deptCode)")]

Spring Cloud Refresh event does not recognize removed properties?

Background:
I have a Spring Boot 1.4 application running with Spring Cloud. My app is using the native profile to pull settings from an external config.properties file. The config server is embedded inside the same application.
In the config.properties file I have added the following setting:
app.setting=helloworld
What works:
When I change the property and send a REFRESH event, relevant beans marked are reloaded and the change is recognized correctly.
What doesn't work:
If I actually remove the property from config.properties, (by commenting it out for instance), the REFRESH event does nothing to actually refresh the application. Spring Cloud seems to not recognize the fact that the property is removed and when the data-binder proceeds to update the state of the world it misses the fact that the property is removed, and the corresponding bean linked to it must also be refreshed and its field set to blank/null, etc.
It looks like the data-binder only looks at what is at the moment available in the configuration and does not keep record of what was vs what is.
The only way to actually disable that setting in the bean configuration state is not by removing it, but by actually setting it to a blank value (which is a new value, given the setting is just a String). Note the field in Java bean mapped to this property has no default value other than null, and the value is not defined anywhere else (as in an embedded application.properties file, etc)
What might I be missing?
Is this a feature? Bug?
Thanks for your time.
Not sure if this is applicable to you, but I had a similar issue with beans annotated with #ConfigurationProperties and registered using #EnableAutoConfiguration:
#ConfigurationProperties(prefix="example")
#RefreshScope
public class MyConfig {
private List<String> values;
}
#EnableAutoConfiguration(MyConfig.class)
public class ApplicationConfiguration {
}
The problem I was experiencing is when you had a YAML configuration like:
example:
- Some
- Values
- Here
removing items from the list did not remove them from MyConfig.values when the context is refreshed.
The cause of this was that registering MyConfig using #EnableAutoConfiguration does not allow you to change the bean's scope, meaning that the bean does not get recreated when refreshing the context. See Github Issue.
My Fix
I removed MyConfig from #EnableAutoConfiguration and explicitly added a #Component annotation:
#Component
#ConfigurationProperties(prefix="example")
#RefreshScope
public class MyConfig {
private List<String> values;
}
#EnableAutoConfiguration
public class ApplicationConfiguration {
}
After this, removing items from the YAML list gets reflected in MyConfig when the context is refreshed.
I've run into a similar issue when refreshing an external config.properties file. The issue manifested itself with my config.properties because it only had a single entry in it.
To demonstrate:
Start by overriding the application properties
application.properties
some.value=abc
config.properties
some.value=xyz
Initially, using some.value will render "xyz"
To show that the value can be updated, change the value in the config.properties
config.properties
some.value=123
Using the /refresh endpoint, refresh the context and then using some.value will render "123"
Now, by removing the property, then we can see the value does not get updated
config.properties
// now empty
Using the /refresh endpoint, refresh the context and then using some.value will still render "123". It hadn't recognised that the field had been removed, nor used the "abc" value from the application.properties.
The issue stems from the class ConfigFileApplicationListener which on line 428, identifies the properties file as empty, so doesn't load the file into the property sources that are later used to compare the new properties to the old in the ContextRefresher class. The scenario appears to keep the old one in memory.
To workaround this issue, when you only have a single property, you could add property like a.b which would force the file to be loaded with the no value and result in the correct functionality.
config.properties
a.b=true
// item removed, but use some property to make sure it's read later
Hope this helps

Spring Boot configuration behaviour with #ConfigurationProperties and Command Line arguments

I seem to be having some funny behaviour with Spring boot on yaml property files im trying to load.
I have a Settings bean that is setup as follows :
#ConfigurationProperties(location = 'config.yml', prefix='settings')
public class Settings {
private String path;
...
}
I've explicitly told spring to look in the config.yml file for property values to bind to the Settings bean. This looks like this:
settings:
path: /yaml_path
This works well, however, I don't seem to be able to override these values from the command line i.e.
java -jar my.jar --settings.path=test
The value that is bound to the settings bean is still /yaml_path but would've expected that the --settings.path=test would override the settings in the yaml.
Interestingly, I've noticed that if i take comment out the path setting from the yaml file, the commandline argument value of test comes through.
Additionally, I've also noticed that if i change my config file from config.yml to application.yml and remove the 'location' attribute from the configuration properties file this gives me the desired desired behaviour, but means that I can't have multiple application.yml files in the classpath as it breaks my multi module application which has configuration files throughout.
Ideal world I would like be able to have modules read configuration from yaml files that contain safe values for that module (i.e. module.yml) and be able to override these values from the commandline if needed. Has anyone figured out how to get commandline arguments passed into the beans this way?
I have created a project on git hub to show case the issue
https://github.com/vcetinick/spring-boot-yaml-test
Running the application displays logging information about what settings are applied. i.e.
java -jar spring-boot-yaml-test-0.0.1-SNAPSHOT.jar --config.path=/test
should override the settings, however, the default /var/tmp is displayed
additionally, when using the application.yml configuration
java -jar spring-boot-yaml-test-0.0.1-SNAPSHOT.jar --app.path=/test
seems to behave as expected where the command line argument overrides the value but only works because its value is defined in the application.yml file.
Looks like the locations attribute is working as designed, however, seems to be at odds with the standard configuration paradigm setup by spring boot (https://github.com/spring-projects/spring-boot/issues/5111). It is meant to override the settings. It looks like this this feature may be removed in a future release of spring boot anyway (https://github.com/spring-projects/spring-boot/issues/5129)

Spring Boot - external property not found

My application is trying to externalize all project properties, some ones will be inside my app and another ones will be in a folder somewhere in Windows.
I set up Spring to execute this way: --spring.config.location=file:///C:\Temp\config\application.properties,classpath:application.properties
As you can see, if the same property exists in both sides, application property will be kept (priority order). I noticed for example some properties such as "server.port" can be found if exists outside folder (file://) but if I create one such "common.acronym-name" my project can not find its value.
Why "server.port" has a different behaviour that one create by me? Is there any configuration I need to tell Spring Boot to see this external property in my project?
#Value("${common.acronym-name:}") //Just find it in application classpath
private String acronymEnv;
Thanks!
To simulate this error, just create a class to handle the banner, for example:
#Component
public class ShowBanner {
#Value("${spring.main.show-banner:}")
private String showBanner;
#PostConstruct
public void init() {
System.out.println(showBanner);
}
}
In this code if you set at external property file the property "spring.main.show-banner=false" the banner still shows in console if it is set before server section. When the banner should not appear. Because the property returns empty.
If I move the property after server section the banner disappears, because return false value as expected.
Keep in mind my application.properties project is empty.
By the way, Even running via Eclipse or java console it happens:
java -jar sample-1.2.3.RELEASE.jar --spring.config.location=file:///C:\Temp\config\application.properties,application.properties
Why?
Believe or not, the order of properties makes difference for external properties be found.
If I set this below order where "spring.main.show_banner" is the first one at the top, my properties can not be found. For example:
spring.main.show-banner=false
server.port=9043
server.session-timeout=1800
server.ssl.key-store=file:///C:/Temp/config/localhost.jks
server.ssl.key-store-password=localhost
server.ssl.key-password=localhost
So, If change to below order, everything works fine:
server.port=9043
server.session-timeout=1800
server.ssl.key-store=file:///C:/Temp/config/localhost.jks
server.ssl.key-store-password=localhost
server.ssl.key-password=localhost
spring.main.show-banner=false
Is there any reason for it? Spring Boot needs to have the properties in right order? Seems the "server" section must the first one in the properties.
thanks.

How do I access Spring properties in a logback configuration

Is there a way to access Spring properties within a logback.xml file?
I know one can import a properties file if you know its location, but I'm using Spring profiles to control where the properties file should be loaded or not.
Is there done kind of connector that asked me to feed Spring data into logback? This would only be at startup; I don't need to be able to do this on the fly.
I'm guessing you do have to import a property file (common property file, non-environment specific one) that will contain the name of the property that you are going to use in the logback.xml, and that you want to optionally override the value of the property for some environment (you need at least one property file containing the name of the property, because you will be using that property in the logback.xml, and you need it to be available to be able to use it).
For the optional environment-override, how about including an additional property file? For example, we use both application.properties and application-${spring.profiles.active}.properties files. Then if we don't need to override the property for some environment, we simply don't include it in the environment specific property file (application-dev.properties, etc.)

Resources