Now, I am going to explain how we can use Spring Cloud Bus to apply configuration changes dynamically to applications while they are up and running. I believe you will be aware of Spring cloud Config which serves sets of configuration information. The configuration file themselves can be backed by source control. Spring cloud clients connect to it automatically over HTTP and retrieve the configuration settings at the start-up time.
But what if we have a configuration change that we need to make after an application has already been running. What if we want to increase the size of our DB connection pool or increase metaspace memory or change the Logging level? The traditional approach is to repeat the Spring startup process. The solution to this problem can be “Polling”. In this Polling, our apps will periodically pull the Config server or some other source for changes. But for configuration changes, if it has to pull every time then it is not a good idea because the config changes are rare.
A cleaner approach is to be to somehow push the changes out from the server to the client. And this is exactly the space that Spring cloud bus addresses.
Spring cloud bus is used to push configuration changes from the config server to the client applications using “Messaging Technology”. Spring cloud bus is a solution that enables a Spring Cloud Config Server to broadcast changes to spring cloud clients. So, it eliminates any need for clients to poll the service periodically. It is based on messaging technology.
The spring cloud config server publishes messages to the message broker and the client becomes the subscribers to the changes.
Setting up the Spring cloud bus is easy. You have to add the below dependency to your Spring Cloud config server’s pom file.
On the client-side, you have to add the same dependency. The code on the dependency is smart enough to understand that if it is on the client-side or the server-side and it works fine. Now, this presumes that your client is otherwise unable to use the spring cloud parent.
The next step is we need an AMQP(Advanced Message Queuing Protocol) server ( Such as Rabbit MQ) to provide reliable messaging. Rabbit MQ is a nice Message broker which is open source and easy to install and run. Spring Cloud Bus works automatically with Rabbit MQ on the localhost. So, this means Spring cloud bus enabled client and server will know automatically how to connect to Rabbit MQ.
So, when we have to make changes to our running application, we have to do the following things:
First, we have to make changes to the relevant files in the repository.
Now, when we commit the changes, there is nothing in the config server that notices these changes. It does not do any polling or listening to the repository. But, if we were to make a rest call to the config server, it would reread our file and pick up those changes.
Next, we would do is that we will make a POST call to the “/bus/refresh/” endpoint on the config server. Notice that this is a post request. So, we have to use curl or some type of rest client.
When the refresh is requested, the config server is going to refresh, and it is going to post a message to the message broker. The message broker ensures a delivery to all the subscribers which is all of our clients that have the spring-cloud-bus dependency. There are ways to fine-tune which clients get what.
Then finally each Java application development goes through its refresh process. And now I am going to explain more details about this Refresh Process.
Spring boot applications can be refreshed at runtime. Spring boot contains a starter called “actuator” and this provides several useful web endpoints. The actuator provides an endpoint that we can use for a health check. When we have an actuator on our classpath, we also have a refresh endpoint. Now, if we have to make a POST call to this refresh endpoint then this would be interpreted as a command to refresh the application. We can use Curl or RestTemplate for this.
Our application might be up and running and processing hundreds of HTTP requests with many database connections, but the Refresh only affects the Beans that are marked with “@ConfigurationProperties” or “@RefreshScope”. The only other thing that is affected is the logging level. This is because logging level is something that we could change fairly often in production and there are no consequences for changing this on the fly.
Now, I am explaining to you about these other two annotations “@ConfigurationProperties” and “@RefreshScope”
This annotation is not new, but it comes to us from spring boot. It is an easy way to set multiple properties quickly instead of putting the value annotations on each one. So, if we have a dozen variables to set using “@Value” annotation, this can get old and fast.
So, instead, if we annotate the entire class with “@ConfigurationProperties” annotation and supply a prefix and provide a setter method, then Spring boot at startup time, automatically populate these properties with corresponding values from the property source that match the prefix and name of the property. Please see the example code below:
In our YAML file, there will be a section that will match the prefix that we are using here in the above code. Also, it will match the properties line up what we need to set. Extra properties would be ignored and anything without the setter method would be ignored. YAML file will look like as below:
You can see that the spelling of the “name” in the above YAML file is not matching with the properties that we have set in the code (name). This is ok. This is called “Relax Binding”. Spring boot understands what we mean here. Camel's case will also be ok, and all caps letters would also match this property without any issue.
Now, if we do a POST call to “/refresh” URL, then any beans with @ConfigurationProperties properties will have their properties rebound. But still, there is a limitation here. It is not enough just to reset those properties. But instead, we might have some initialization logic that needs to be rerun. Now, for our “ProfileController” example here, rebinding the properties is completely fine. Because the property is just used in the controller. Now, something new got introduced in spring cloud but not in spring boot is “Refresh scope”.
RefreshScope gives us the ability to safely incompletely reload the bean without having to worry about the effect that it will have on the other beans that are presently referencing. Refresh scope allows for hot-swapping of old and new copies of the bean at runtime. So, when we make a POST call to refresh, the entire bean is reloaded. It is not limited to property rebinding like the case of @ConfigurationProperties. Now it is reloaded in a Safeway. Please see below the snippet of code:
The side effect of the refresh scope is that the bean becomes lazy meaning that it is not reloaded until the first time that it is used. This is ok but any configuration issues or any post construct issues will not be discovered until the first time the bean is used. Now, you can see from the above code that our bean uses @RefreshScope. You can also see that I can revert to the “@Value” annotation. We can use also @ConfigurationProperties with @RefreshScope. With the @Value annotation, I do not need getters and Setters methods, but I will lose here the “Relax Property Binding” that is provided by Spring boot.
Refresh scope works by using the Proxy pattern and it is one of the useful use cases for the Proxy pattern. When the application context loads, Spring creates a proxy for the actual target bean. The proxy either implements the same interface as the target bean or it extends it depending upon whether an interface is present on a target Bean. It has the same method signature as the Target Bean.
The main point is that the proxy looks exactly like the Target Bean to anyone referencing it from outside. Now when we do dependency injection, other beans do not get the original bean but then get a reference to the Proxy. When the caller makes a method call, the proxy simply turns around and calls a method on the original bean.
Now on refresh what happens is a new replacement bean is created and the target reference on the proxy is switched to the replacement. That means on refresh, the “target” bean is changed to the newly created bean. Older bean is dereferenced. Any calls to the original bean that are currently executing are unaffected. But any future calls to the method will go to the new bean. Please look at the below diagram for a better understanding:
So, the beauty of the refresh scope is that the proxy makes it safe for the existing threads to finish up whatever they are working on while the future gets switched over to the new version.
Now, we will implement this in our example demo. I am going to setup our spring cloud config server to use the Spring cloud bus and also I am going to setup Rabbit MQ.
I am going to explain to you about the API Gateway and Spring Cloud Zuul and show you how it can be used to easily implement basic routing.
Let’s assume about the applications that we have implemented will look like the below structure:
We have introduced lots of concepts like Eureka and Config server to help services find each other, configure themselves, update themselves and call each other. This works fine with the assumption that our network is high speed and secure and that bandwidth is unlimited, and latency is zero. But always you cannot assume a fast-secure network. So, we have to make some improvements.
Another fundamental issue is that multiple HTTP calls are made to get each sentence in the above example diagram. The client needs to get the response back in a jiffy.
We could have a dissimilar client having different needs. What if some of the services are not relevant for some of the clients. The issue here is that the Microservice is built to be focused and simple, but the clients have specific needs to assemble the content or use the services in the ways that our services should not have to concern themselves with. We need something in between like an Adapter. So that can serve the clients directly by taking care of the various backend calls on their behalf. This is exactly where the “API Gateway” fits in.
Here, offshore java development services provider have explained to you about the real-time implementations of the Spring cloud bus with Eureka and the config server. If you are not familiar with Eureka and Config Server, then please read our specific blogs on Eureka and Config Server. Try to implement yourself as the API gateway in your project. You can also read our more advanced blogs to learn about the implementation of the Spring API Gateway.