How to create custom annotation that will add new property source - java

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)

Related

Use of PropertySourcesPlaceholderConfigurer?

I am starting to learn Spring annotations. I'm currently using the #PropertySource annotation in my Configuration Class to resolve properties values and everything works fine, but then I read about PropertySourcesPlaceholderConfigurer.
When or why I should use that?
From #PropertySource javadoc
...
Note, however, that explicit registration
of a PropertySourcesPlaceholderConfigurer via a static #Bean
method is typically only required if you need to customize configuration such as the
placeholder syntax, etc. See the "Working with externalized values" section of
Configuration #Configuration's javadocs and "a note on
BeanFactoryPostProcessor-returning #Bean methods of Bean #Bean's
javadocs for details and examples.
Specifically, if no bean post-processor (such as a PropertySourcesPlaceholderConfigurer) has registered an embedded value resolver for the ApplicationContext, Spring will register a default embedded value resolver which resolves placeholders against property sources registered in the Environment.
...
Well, if simple words if you need set up or get more control over property configuration bean such as PropertySourcesPlaceholderConfigureryou could define it. Otherwise it can be ommited.
But if you use version of Spring prior 4.3.0, this bean has to be declared for resolve #Value.
For get more details:
6.Configuration using Raw Beans in Spring 3.0 – the PropertyPlaceholderConfigurer
javadoc #PropertySource
I hope it'll a little help you)

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.

Access properties dynamically with Spring

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.

How to create a custom Spring PropertySource that depends on a Spring Bean

I'm attempting to use the spring-cloud stack for a project that would use Zuul. In my organization we have a custom configuration stack that is xml-based and does property composition and hierarchical overrides. Because of the way this configuration is handled, I've struggled to create a PropertySource for it.
My custom PropertySource must use my Config bean, but because the PropertySources are initialized during the bootstrapping of spring boot, the application context is not fully initialized yet and I can't get to my custom Bean that exposes our xml-based configuration system.
#ConfigurationProperties appears to be entirely biased toward .properties and .yaml files. The Config bean is initialized in an ApplicationContextInitializer. Is there a way to delay the resolution of the ConfigurationProperties within the various services so I can construct my custom property source using my Config bean after it is initialized?
I originally attempted (well before asking the question) to create a custom PropertySourceLocator in my config (as mentioned by Dave Syer and well documented in the link he gave) and register it with my own spring.factories (Again, demonstrated in the helpful link given by Spencer Gibb in the comment.) The problem is that my property source needs to be configured after some work that is done in an ApplicationContextInitializer and the property sources all seem to be resolved before that occurs (at least those wired in as a factory for org.springframework.cloud.bootstrap.BootstrapConfiguration). I guess I hinted at this by stating that I needed a particular bean in my PropertySource that I couldn't get from the ApplicationContext at the time.
Anyway, to get around that, I am now registering the property source in an PriorityOrdered ApplicationContextInitializer to take place after another one that initializes my config object. Something like: context.getEnvironment().getPropertySources().addFirst(myPropertySource);
This seems to get my property source into the environment at the correct time and allows me to perform customization of the context before hand as needed.
In Spring Cloud you would need to register some BootstrapConfiguration (per the user guide: http://projects.spring.io/spring-cloud/spring-cloud.html#customizing-bootstrap-property-sources) that has a PropertySourceLocator bean. It shouldn't be any harder than that.
P.S. #ConfigurationProperties is not biased toward .properties and .yaml files - it binds to the Environment which knows nothing about file formats.

Categories