Implementing Dynamic Resource-Based Services in Java With Ressor
Join the DZone community and get the full member experience.Join For Free
Ressor is an open-resource framework for developing dynamic Java-based services and components in which business logic is based on some resource data. The resource could be anything — file on local File System, YAML configuration from GitHub repository, etc.
Consider, for example, a weather prediction service or a stock market price provider, which pulls new data over an HTTP endpoint. These kinds of services are useless if they operate with stale data, so they should detect and reload continuously.
You may also like: Dynamic, Modular Microservices With Java EE
The key idea of Ressor is to hide away all the complexity related to working with data sources, content parsing, and dynamic reloading. It provides a declarative API, with which you define services once and use for the whole application runtime.
How it Works
Ressor generates a special proxy class that inherits your service type. Under the hood, this proxy delegates all method calls to the most up-to-date instance of your service/component. To create it, it loads data from the provided source, parses it using translators, and calls the constructor/factory method of your class.
Ressor provides a declarative API, implementing the most popular sources and file formats. During service instantiation, you should define what your source, resource, and translator are. Thus, after service is created, you can subscribe to further resource changes. Versioning is also supported using different reload strategies, depending on the kind of data source. This allows to reload only the data which was actually changed, saving the network/disk bandwidth and CPU resources.
This approach aligns best with IoC/DI frameworks, such as Spring, where you register the beans only once during context startup. You can safely do it with Ressor services as well. In this case, Ressor will implicitly make sure they are always up-to-date.
Dynamic Feature Toggle Example
Consider you are about to implement an extremely simple Feature Toggle service for your application. It will be configured using a simple YAML file stored on the GitHub repository. Whenever the feature toggle state is changed via commit to this repository, your application should enable/disable the given feature at the runtime. Following is a data model:
It's very simple — we have a feature name and its current state. Having this model, we can implement our service:
Our service takes a list of feature toggles as an input and builds a state map. Then, we can check whether the feature is enabled using
Now, it's time for Ressor to create a service instance and start fueling it with data from the GitHub repository:
Let's describe the most important parts line by line:
#4: Declare that we expect data to be in YAML array format. Ressor will parse it using Jackson into List<FeatureToggle>.
#5: Declare that the source will be a Git repository from the remote URL.
#8: Declare the path to file inside the Git repository.
#9: Creates a proxy class instance, cloning Git repository and translating YAML content into
You can always re-use the source for multiple services.
You can instantiate your service asynchronously, but in that case, you need to provide an initial instance, which will serve until the first reload happens:
Making Service Reloadable
We would like Ressor to keep
featureToggle service with only up-to-date information. Someone may disable some features by committing a change to a toggles.yaml file in the GitHub repository.
This can be achieved by simple polling using Ressor:
It will be performing git fetch command every 5 seconds for the source repository on the background. If any file change is detected (for the current branch), a new instance of
FeatureToggleService will be created and replaced inside the proxy.
featureToggle instance can be, for example, registered once as a Spring bean during application startup. Ressor guarantees that it will eventually contain the most recent data.
Once Ressor creates a service instance, it can be used anywhere for the whole application lifetime:
You can find the full example code here. You can try it by running yourself. There are also lots of other examples.
Releases are available via Maven Central. Sources implementations are bundled as a separate modules.
Ressor idea is quite straightforward: take complete service implementation and fuel it with the translated data from the given source, implicitly reloading it when needed. Apart from Git, Ressor has various other data sources: file system, HTTP, Amazon S3, etc. There are more cases and features that were not covered in this article.
Opinions expressed by DZone contributors are their own.