This is a continuation of previous blog posts:
Source code for this part can be found at GitHub in spring-cloud-3 branch.
Let’s say we don’t want to hardcode the URL to Config Service in our application properties because it may change from environment to environment. Of course, we could pass this property as JVM environment variable on each environment, but then we need to worry about it in application startup scripts. Instead, we could use service registry (such as Netflix Eureka) and only use a friendly name for a service, instead of its URL.
Here we will update Config Service and Pricing Service applications to use service discovery mechanism with Spring Cloud Discovery.
Configuring Eureka Server
Similarly, like we configured Config Service we will configure Eureka Server. We can generate Config Service app with Spring Initializr at http://start.spring.io again.
All we need is to choose “Eureka Server” and “Web” from dependencies.
This would generate app with maven dependencies in pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
Then we need to enable discovery server with annotation on main class:
@EnableConfigServer
and configure Eureka Server to not try to connect to itself - add resources/application.yalm
with content:
server:
port: ${PORT:8761}
eureka:
client:
registerWithEureka: false
fetchRegistry: false
server:
waitTimeInMsWhenSyncEmpty: 0
Configuring Eureka clients
In Pricing Service and Config Service we need to add a dependency
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
and add Eureka client autoconfiguration with annotation
@EnableEurekaClient
Note the fact that in some examples in the web you may find annotation @EnableDiscoveryClient
which basically does the same if you have Eureka dependencies in the classpath, but it has subtle difference.
There are multiple implementations of Discovery Service in Spring Cloud, such as Eureka, Consul, Zookeeper.
@EnableDiscoveryClient
lives in spring-cloud-commons and chooses the implementation from the classpath.
@EnableEurekaClient
lives in spring-cloud-netflix and only works for Eureka.
Once we have an annotation on main class, when we start the app, it will try to contact the Eureka server on http://localhost:8761
(the default value of eureka.client.serviceUrl.defaultZone
)
Now start Eureka Service and Config Service and go to Eureka console at http://localhost:8761
You would see an UNKNOWN service in the registry.
This is because we have not specified Config Service name.
In Config Service create file resources/bootstrap.properties
and add property:
spring.application.name=config-service
This is a similar property to the one which we have added in Pricing Service bootstrap.properties
and this is how Spring Cloud allows identifying a service by name.
We could actually add this property in application.properties
and in this case it would still work but there are cases when the name is required yet before application context starts to initialize
and bootstrap.properties
is the one which is loaded at very first place when application starts so it’s safer to put spring.application.name
already there.
Now when we restart Config Service it will be named in Eureka dashboard list.
Similarly, we can configure Pricing Service with Eureka.
We need to add the same dependencies as we added in Config Service, then @EnableEurekaClient
annotation on main class.
Pricing Service already has spring.application.name
property configured before.
What is left is to replace hard-coded URL to Config Service with Eureka discovery.
Before we added Eureka we had such configuration in Pricing Service bootstrap.yaml
:
spring:
application:
name: pricing-service
cloud:
config:
uri: http://localhost:8888
Even though we added Config Service registration in Eureka, by default it does not affect other services which use Config Service.
We have to explicitly tell that we want to use Eureka client library to discover Config Service by setting property spring.cloud.config.discovery.enabled=true
in Pricing Service bootstrap.yaml
.
Spring documentation states: The price for using this option is an extra network round trip on startup to locate the service registration. The benefit is that the Config Service can change its coordinates, as long as the Discovery Service is a fixed point.
Eureka client will try to find service named configserver
in Eureka registry, but won’t find such, as we named Config Service differently by setting the property spring.application.name=config-service
in Config Service bootstrap.yaml
.
Then we have to explicitly define the name of Config Service in Pricing Server bootstrap.properties
. The final configuration will look as follows:
spring:
application:
name: pricing-service
cloud:
config:
discovery:
enabled: true
service-id: config-service
When we start Pricing Service we should see a log like:
c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at: http://192.168.43.107:8888/
It means Eureka client managed to resolve the location of Config Service.
It was handled automagically by Spring, but we have not seen how to call other services manually from java code (e.g. with RestTemplate).
I will explain how to do it in next post soon.
comments powered by Disqus