I'm studying Spring-Cloud-Netflix and I learned that Archaius was used for Hystrix runtime configuration. (https://ahus1.github.io/hystrix-examples/manual.html#archaius)
I also found that Archaius was a soft-dependency since V1.5.0 (https://github.com/Netflix/Hystrix/pull/1083): "Archaius is now a soft-dependency of Hystrix, so you can supply your own configuration mechanism."
My question is, is it easy to configure Hystrix with Spring-Cloud-Config at runtime? I did some research but haven't found any examples.
Appreciate any ideas.
After several days' research, I managed to dynamically configure Hystrix properties with Spring Cloud Config. I also made a small demo on configuring the Hystrix instance property at runtime.
First, each Hystrix property has four levels of precendence:
Global default
Dynamic global default
Instance default
Dynamic instance property.
Where the 1st and 3rd levels only support static configurations. Since the 2nd level (dynamic global default) was not discussed a lot in the Hystrix Wiki, I choose the Dynamic Instance Property for runtime configuration. However, I believe my method should apply to Dynamic Global Default as well.
The practice is simple. First pull a config value from Spring Cloud Config using the #Value annotation:
#Value("{timeoutInMilliseconds:1500}")
String timeout;
Then use the string timeout in your Hystrix instance:
ConfigurationManager.getConfigInstance().setProperty("hystrix.command.HystrixHelloWorld.execution.isolation.thread.timeoutInMilliseconds", timeout);
Where the ConfigurationManager.getConfigInstance() is an Archaius method, returns a configuration instance. .setProperty() sets the property
Related
I have a confusion regarding datasource autoconfiguration in Spring-boot. From what I have read, we have to specify the datasource properties in the form spring.datasource.*. But my application code works fine if I supply property name in the form SPRING_DATASOURCE_*. Is there any reason that I am missing, due to which it works? Please clarify.
I think You've come across a feature of spring boot called Relaxed Binding.
It allows using some "relaxed" rules for binding to ConfigurationProperties. So essentially both ways of definition have the same effect in your application.
Here you can find a link to the relevant chapter in the official documentation
Spring Boot has so-called Relaxed Binding
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-relaxed-binding which allows you to define configuration in different ways:
acme.my-project.person.first-name
acme.myProject.person.firstName
acme.myProject.person.firstName
acme.my_project.person.first_name
ACME_MYPROJECT_PERSON_FIRSTNAME
The latter is often used when passed via environment variables.
I have a toml file being used to configure an application that uses Spring framework's KafkaListener annotation with the following signature:
#KafkaListener(id = "id0", topics = "some.hard.coded.topic.name")
I have a configuration manager class that reads a TOML file and configures various application settings based on the environment the app is running in. One of these is the topic to listen to. However, I do not know how I can pass this in to the Kafka Listener annotation. My understanding is that this can be done using SPEL in conjunction with yml files but I'm kind of locked in to using TOML here. Can anyone advise?
The topics property of the #KafkaListener indeed supports a SpEL including BeanFactory access, so if you have some bean which reads that TOML file and represents it as some set of runtime properties, e.g. getters, then you definitely can get a gain of the SpEL there. For example:
topics = "#{myTomlService.getTopic()}"
where myTomlService is a bean name for the mentioned service.
I have a spring-boot app that autoconfigures an instance of Netflix's DynamicPropertyFactory. This enables us to read any properties spring is aware of plus any additional sources we specify.
The issue arises when we change a spring property that is used in core spring classes. For example logging.level.org.springframework.web=INFO is used on core classes or spring before, during, and after applicationContext setup. If we change this property while the application is running to say logging.level.org.springframework.web=TRACE...
dynamicPropertyFactory.getInstance().getStringProperty() eventually realizes the change. However, the spring core classes continue to log at INFO rather than change to TRACE as expected.
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.
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();