External URL configuration in microservice - java

I have multiple microservices which communicates with each other through REST calls.
I have used spring boot and spring rest and have configured the URLS of the rest end points in application.properties file.
Now the problems is if the URL for one end point changes then I to have to manually modify all the property files of the services which are calling that particular end point which has got changed.
Is there a workaround for this so that the URLS can be somehow placed in a centralized location so that any modification does not impacts the other services which are using it.

You can use spring-cloud to achieve this. Usual way used in spring-cloud is by configuring the required properties in a git repo. And then those properties can be accessed by any micro-service you want with minimal configurations. You can refer projects in this repo
limits-services acts as a client that needs certain properties those are configured in spring-cloud-config-server. Hope this helps.

In case with microservices you can use Spring Cloud Config (Spring Cloud Config, Spring Cloud Config Server). It's very usefull and you can update your configuration at runtime.
Spring Cloud Config provides server and client-side support for externalized configuration in a distributed system. With the Config Server you have a central place to manage external properties for applications across all environments. The concepts on both client and server map identically to the Spring Environment and PropertySource abstractions, so they fit very well with Spring applications, but can be used with any application running in any language. As an application moves through the deployment pipeline from dev to test and into production you can manage the configuration between those environments and be certain that applications have everything they need to run when they migrate.

As others have mentioned you can use Spring Cloud Config Server to remotly load your application configuration. All you need is git repository containing your configuration.
Spring cloud configuration supporst Git, database as your store for configuration.
Idea is to create an spring-boot app that can provide configuration to other applications.
#SpringBootApplication
#EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
You can configurae port and provide your git repository using key spring.cloud.config.server
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo
At client side, if you have spring-config in your classpath, application will try to connect to an application runnign at port 8888 to retrieve configuration.
More information can be found here.

may put configuration inside a database.
after that need have one centralize cache service that used by other services, can be .jar service,
then the values can be load inside a cache class in this service,
then in the front end side need have update button for updating the cache after modify the URL value in the database, so then all impacted services can use new value.
and also to be easier may have stand alone UI for update those configuration rather than updating database directly.

You can use Microconfig.IO to manage your service configuration and it's placeholders functionality to reference configuration values of certain services from others. So in your case you configure your deploy url in your server and put placeholders on it in your clients. This allows you to edit value only in one place and then everyone who depend on it will get it automatically.

Related

Load application.properties when the config server is not resolved

My project has a bootstrap.yaml and a config server that deliver its appropriate profile. Everything is working great but I have to accomplish some others task like CI and CD.
My problem comes because the Jenkins machine is not allowed to resolved external domains and try to compile and run the Spring boot app without an a profile.
So my question is:
Is there a way to load application.properties when the config server
is not resolved?
Yes, there is a natural way based on the order in which Spring Boot loads PropertySources.
You can include properties you want to be applied in application.properties.
In case config server is not available - properties from application.properties will be used. If config server is available - you'll receive properties from there.
You might also want to disable config server connectivity for your CI using environment variable SPRING_CLOUD_CONFIG_ENABLED=false.

Spring boot Cloud Embedding Config Server to get properties from Git repo for each request

I am using Spring Cloud Embedding Config Server to get the configuration from Git while server startup. Its working fine. Below is my config.
bootstrap.properties
spring.application.name= "credentialInfo"
spring.cloud.config.server.bootstrap= "true"
spring.cloud.config.server.git.uri= "https://11111#bitbucket.global.company.com/scm/~11111/spring-cloud-config.git"
spring.cloud.config.server.git.username= "aaaa"
spring.cloud.config.server.git.password= "bbbb"
Now I have to get the properties from Git repo for each request with username and password collected from Customers.How can I achieve this ..?
Normally client application get properties from git though config server when startup and when call to "actuator/refresh" endpoint.
I'm that the requirement as you state its doesn't work well with Spring Boot.
When configurations are read (no matter from where, including the configuration service) they are used to configure spring beans during the startup.
For example, if you have a configuration of, say, db host, this configuration is supposed to be used by bean responsible for database connectivity (DataSource)
The point is that by the time that Application Context starts, beans are already configured.
Its true that some beans having refreashable scope define a custom logic to get "re-initialized" as a consequence of calling /refresh endpoint, but this is not what you're asking for (at least as far as I understood)
Instead you say, that the client does something during the application startup and this action should lead to beans change. This is potentially a very expensive operation and I don't think you should go in this direction. Usually beans are not re-created during runtime (of scope singleton, and the chances are that most of the beans are of this scope)

What is the right approach for extending Spring Cloud Config Client?

I want to replace Basic Authentication for Spring Cloud Config Server with oAuth implementation. Let's leave Config Server alone for now and focus on changes for Config Client. Obviously I don't want to write my own implementation for whole thing, but instead execute my own logic and fallback on standard Config Client. Also I have to pack my changes into library since I will use it in multiple micro-services.
Long story short I want to achieve following:
1a. Create custom Starter which will contain Spring Cloud Config Client as dependency. Is it even doable or necessary?
or
1b. Create custom Starter with only my custom logic which will be executed before Spring Cloud Config Client. In this case each micro-service will have Spring Cloud Config Client and custom Starter as dependencies. How can I manage execution order and inject custom logic results into Config Client?
2.Introduce new bootstrap settings. e.g. spring.cloud.config.custom.username and spring.cloud.config.custom.password (Optional).
3.Introduce custom annotation for custom Starter. e.g. #enableCustomConfigClient (Optional).
I started with building custom Starter with following code in /resources/META-INF/spring.factories:
# Bootstrap components
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
com.example.greeter.config.ConfigClientBootstrapConfiguration
But this code invoked after profile is set, not the first thing like Config Client does.
Any suggestions and especially code samples are appreciated. Thanks!
Posting approach I chose for future reference.
Create new package which will be executed on top of / before Spring Cloud Config Client. Two main features here:
Create file src/main/resources/META-INF/spring.factories with org.springframework.cloud.bootstrap.BootstrapConfiguration={YOUR_CLASS}
In {YOUR_CLASS} apply custom logic. Don't forget to use #org.springframework.core.annotation.Order({YOUR_PRECEDENCE}) and fact that Ordered.LOWEST_PRECEDENCE will be executed first
Build jar from previous step and include it into your project (as local file or via artifactory)
Add Custom logic to Spring Cloud Config Server so it can use JWT.
Working example is here: https://github.com/ka4ok85/spring-cloud-config-client-jwt

Spring Cloud Config server inside a Spring Boot app with MVC

I'm inserting a Spring Cloud Config server directly into my existing Spring Boot App, by adding the module dependency and #EnableConfigServer. Everything works as expected except I just realized that the config server URL mapping is hijacking some of my existing API endpoints due to they are sharing the same server.port
For example, I had an existing page at v1/docs/index.html, and this will be now mapped automatically to org.springframework.cloud.config.server.environment.EnvironmentController#labelled which has
#RequestMapping("/{name}/{profiles}/{label:.*}")
public Environment labelled(#PathVariable String name, #PathVariable String profiles,
Wondering is there anyway I can separate config server to a different port? Or add a special prefix to it to avoid URL mapping conflicts? Or given the current configurability it's just a bad idea to utilizing existing API servers as a config server?
Found the answer I need after reading the document more carefully:)
https://cloud.spring.io/spring-cloud-config/spring-cloud-config.html#_spring_cloud_config_server
To change the location of the server endpoints you can (optionally) set spring.cloud.config.server.prefix, e.g. "/config", to serve the resources under a prefix. The prefix should start but not end with a "/". It is applied to the #RequestMappings in the Config Server (i.e. underneath the Spring Boot prefixes server.servletPath and server.contextPath).

Externalise REST endpoint in Websphere Application Server

I have to consume a REST endpoint from the Utility class written in Java. Utility class is deployed in application server as part of my EAR. The REST resource end point will vary depends on environment like (DEV, TEST, PRE-PROD and PROD). So, I want to externalize the end point and should be able to change it without code change.
The normal way to do this is to configure a URL in JNDI, and do a JNDI lookup for the URL and configure the resource in each environment as it needs to be.
In the Websphere console under Resources there is a place for "URL" which would seem to be place you would want to put this and then do the lookup in code (or wire in the lookup via Spring or your personal preference).

Categories