stickycode-extended-config
Introduction
StickyCode from StickySource allows for the separation of the configuration from the wiring process for DI containers like Spring (and Guice, CDI, etc). This allows all of the configuration to happen at once (and thus all missing configuration to be made available at once) and in this case, for configuration to be reloaded without the wiring of the application being affected.
This project enhances and changes StickyCode and provides a Spring scanned configuration file to support the @ConfigKey
annotation injects System properties into your Spring objects - but lets you choose the name.
@Configured
support is dropped as it is not considered a best practice. StickyCode is very well engineered allowing pieces to be plugged and played, thus allowing this decision.
This project is designed to work in the Spring Boot infrastructure and operate with Kubernetes where config files and secrets can be reloaded without re-starting the Pod. It can of course, work without either.
Annotations
There are as follows:
-
@ConfigKey(value)
- (field level) this is used to denote a field to be injected into to be injected into. Unlike the @Configured annotation from StickyCode which uses the name of the field with the name of the bean, this lets you choose the name you are looking for in your configuration. If no value is specified as the value for the variable, failure to provide one in configuration will cause the application to fail to start. All missing configuration will be delivered in one go. -
@PreConfigured
- (method level) this is a method that can be called before configuration starts -
@PostConfigured
- (method level) this is a method that is called once configuration has been injected. -
@CompleteConfigured
- (method level) this is a method that is called once all beans have had their configuration injected and post configured completed. This is more typically used for orchestration but because of the way the DI container works, you are not assured that any ApplicationAware methods have been triggered on the beans.
For use in Spring, there is an annotation allowing configuration of StickyCode.
-
@EnableStickyConfiguration
- this triggers the Spring configuration necessary to load the beans to make this infrastructure work. It uses Spring style @Configuration and @Import to do this.
Notes:
-
@PreConfigured
,@PostConfigured
andCompleteConfigured
can be annotated on a class that does not have any @ConfigKeys. -
Configuration and the method calls can be out of order of injection at the moment.
-
All method calls are synchronous - this should change in the future.
-
All injected fields must be objects, not primitive types because of JVM constraints
e.g.
@Component class MyClass { @ConfigKey("person.name") String name @ConfigKey("person.age") Integer age @ConfigKey Boolean alive // myclass.alive @ConfigKey List<String> aliases // myclass.aliases @ConfigKey("person.legCount") Integer = 2 // defaults to 2, you don't need to configure it @ConfigKey Map<String, Integer> childrenAges // myclass.childrenAges }
in system properties you would have
person.name=fred person.age=35 myClass.alive=true myClass.aliases=The Hammer, Sooty, Sweep myClass.childrenAges=Barbara:7, William:2
You can include in your class a @PostConfigured annotation to then do post processing on the configuration.
@Component class AlsoMyClass { @ConfigKey String parts = "gibberish" @ConfigKey String password @PostConfigured public void configure() { // do something here } }
Configuration Sources
This project only supports one, system properties - but it loads external configuration into the system properties. StickyCode itself supports anything as a configuration source, a central tenant being that your configured code should not need to know where its configuration is coming from.
There is nothing in ConfigKey’s extension that requires System Properties, but the WatchedFilesApplicationRunListener
for Spring Boot only supports this.
Alternatives
We can use the @Value annotation from Spring, but this has a number of "issues":
-
@Value annotated fields in base classes will not pull their configuration settings when the bean is configured
-
@Value requires you to specify where your properties are coming from, which generally is undesirable as the source of configuration is extensible.
-
@Value’s default mechanism is clumsy, requiring error prone stringization of defaults
-
@Value does not allow reconfiguration without re-wiring. In a Kubernetes world, this is essential.
External configuration and Spring Boot
With Spring Boot, External configuration is passed on the command line using -P arguments. These files may be YAML files or Properties files. They must also be in the file system (this does not support classpath loading). As per the Bath Boot style, there can be many of them.
The default timeout for the watch timer is 15 seconds, if "sticky.timeout" is set to another value (in seconds) it will swap to that sleep mode. A thread is consumed sleeping and then checking the files for timestamp changes. If you are not using Spring Boot, you will not be affected by this. Also, if there are no files to watch, it will also not trigger. If you set the sticky.timeout to zero, it will never check for updates.
Working without Spring Boot
Just load your properties into System Properties and import the resource.
Web Usage
The artifact includes a web fragment, if included in a Servlet 3.x container, it will automatically be added to the global web.xml
Other Spring usage
Anyone using the Artifact outside of a web container will need to get the StickyBootstrap object and call "start" on it (see the StickyBootStrapServlet for an example).
Notes
-
if you don’t give a default value and the user doesn’t provide a value, the initialization of your application will immediately fail (FAST FAIL)
-
Obviously this all requires Spring (this section).