Access properties dynamically with Spring - java

I have a Spring application with xml configuration (v4.0.8) where I need to access properties dynamically rather than using #Value annotation. I tried using tho methods for this, one of them is using #ConfigurationProperties with a Map which gives me all properties in a map, and the other way is using Environment.getProperty.
Both methods are getting the properties from the propertySources of the Environment. Unfortunately that contains 5 property sources including system properties, etc, but not my properties files. Therefore I cannot access my properties.
I'm adding my properties using EncryptablePropertySourcesPlaceholderConfigurer from jasypt which is a simple implementation of PropertySourcesPlaceholderConfigurer that decrypts encrypted property values. PropertySourcesPlaceholderConfigurer does not add properties to Environment.propertySources and I couldn't figure out how can I extend it myself rather than using jasypt implementation and add them to property sources manually.
Two notes:
#Value annotation works fine, because it's not using Environment but goes through configurers during bean creation. There's not problem with that.
I have a spring boot application where I cold achieve my goal appending to Environment.propertySources by listening to ApplicationEnvironmentPreparedEvent of spring boot and adding my properties to Environment rather than implementing PropertySourcesPlaceholderConfigurer. But this is only applicable to spring boot applications and my legacy application is not a spring boot app.

Related

Spring config #RefreshScope

Can I use #RefreshScope (along with #Value on a property) only in Cloud config server or can I use without config server as well? I'm trying to use it without config server. I am trying to fetch #Value property by changing value in a .property file and trying to request again, will I get updated value? Is that possible?
No, you should use it along with Config server otherwise you won't be able to read the update properties on fly. Follow this article and have a look into this if you face any issue loading updated properties dynamically.
In theory, you could refresh the application context, but I wouldn't
recommend this. Spring Cloud has provided an annotation to mark a bean
as refreshable. By adding spring actuator, we can refresh those beans
on the fly.

How to avoid putting #RefreshScope on multiple beans in my application

We are externalizing configuration of our microservices (spring boot based) using spring cloud.
As per my understanding on Spring Cloud, to enable the beans loading refreshed/updated values from Config server we need to do 2 things in Spring Cloud Client:
add #RefreshScope on the beans reading values from property files
using #Value
add spring actuator to provide /refresh endpoint to
refresh the context.
Scenario:
We have 100s of classes reading values from property file using #Value.
I have to mark all these beans refresh enabled using #RefreshScope annotation.
How can I avoid putting #RefreshScope annotation on all these classes.
Is there any shortcut or spring cloud feature to get around this situation.
You may want to look into Spring Boot feature called #ConfigurationProperties. It is designed to better organize several external configuration options.
According this Github issue, it should work for spring-cloud without #RefreshScope usage.
EDIT (reaction on comment): Maybe you are missing point of #ConfigurationProperties. With this annotation, you wouldn't use it in other configuration classes. You would have dedicated class (or few classes) only for reading and providing properties. Other configuration classes would inject this configuration holder bean.
You could encapsulate your #Values into one (or several) ConfigurationService bean which is #RefreshScoped and autowire this service into your classes instead. That way you only have a small amount of request scoped beans and your services can stay singletons.

How to create custom annotation that will add new property source

I have several spring boot applications in which I want to place a custom annotation (in some bean). The annotation will have one field (e.g. propertyValue). That value I want to add to the Environment as a part of a new PropertySource.
My idea is to create a bean that will inject Environment and then add a new PropertySource to it. The missing piece is how to connect custom annotation with this bean.
Any ideas?
So you want to use different property file for different environment. Spring Boot handles this already without need for custom beans or annotations.
Just use Profile-Specific Configuration Spring Boot feature. You can define profile via system property (e.g. -Dspring.profiles.active=PROD-US-EAST-REGION)

How to make Spring Boot fail fast when did not found database configuration

I'm running a Spring Boot application.
When there's no application.properties file in standard config paths it is not loaded and default configuration seems to be loaded.
application.properties:
spring.datasource.url=jdbc:sqlserver:...
Because of that, Spring Boot creates empty database with scheme without data which leads to empty program output.
How can one prevent Spring Boot from loading database default configuration?
you can use something as follows exclude in #EnableAutoConfiguration annotations to exclude Datasource default configuration. Reference
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
I don't know if there is any provision to make the app fail fast.
In order to stop Spring-Boot from autoconfiguring certain features for you, you need to explicitly exclude the corresponding class from the auto-configuration config:
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
Note: using this annotation you are taking back the responsibility from Spring to setup things for you, so you need to configure your DB properly from now on.

How to modify properties resolved by Spring before their injection into beans

I need to provide support for external preperties decryption in Spring application. I planned to use a mechanism from spring-cloud-config, which is triggered after the Environment is ready and add decrypted properties with higher precedence. Unfortunately it heavily relies on Spring Boot bootstrap mechanism which emits ApplicationEnvironmentPreparedEvent. Looking into the Spring Framework code the environment and context creation is highly coupled and it would be rather hard to run my own code between that. The application I am working with is a large, multi module "standard" Spring MVC application and I would not like to convert it into Spring boot application right now.
Question:
How could I execute my code after the environment was created and before the context creation (to modify properties before they will be injected into "normal" beans) in Spring (not Spring Boot) application?
Alternative question:
Is there any other way to get control over properties being injected into beans (for modify values originally resolved by Spring)?
You can create a custom ApplicationContextInitializer which adds decryption or whatever to the PropertySources of your choice.
We do something similair in one of the application I currently develop. After loading some custom properties from files and databases we wrap all the available PropertySources in a EncryptablePropertySource because several properties are encrypted (We use the Jasypt library for that).
Use #Value("${propname}") annotation on a setter method, instead of using on the field.
You can write code to handle transform/validate the property in the setter method, and then assign to the field.
In the mean time I have found customizeContext method in ContextLoader which reads defined ApplicationContextInitializers. It is executed after the environment was created and before the context is reloaded, so decryption in an initializer should work (at least in the base case):
ConfigurableEnvironment env = wac.getEnvironment();
(...)
customizeContext(sc, wac);
wac.refresh();

Categories