Microservice discovery with Spring Boot and Eureka

One of the standard problems with Microservices Architecture is the issue of service discovery. Once we’ve decomposed our application into more than a handful of distinct microservices, it becomes difficult for every service to know the address of every other service it depends on. Configuring dependencies from inside a microservice is impractical – it distributes configuration among all the microservices. It also violates the DRY principle – multiple microservice instances will need access to the same configuration settings. What’s more, it goes against the Dependency Injection design that’s supposed to be one of the benefits of the Microservices Architecture.

The standard solution is to delegate location of microservices to a new microservice. In keeping with the Single Responsibility Principle, this ‘discovery’ microservice is responsible for tracking the locations of all the other microservices and nothing else.

Netflix’s Eureka is an implementation of a discovery server and integration is provided by Spring Boot. Using Spring Boot, we can build a Eureka discovery server and have our microservices register with it.

Building a Eureka server

Spring Boot’s opinionated design makes it easy to create a Eureka server just by annotating the entry point class with
@EnableEurekaServer:

Java

1

2

3

4

5

6

7

8

9

@SpringBootApplication

@EnableEurekaServer

publicclassApplication{

publicstaticvoidmain(String[]args){

SpringApplication.run(Application.class,args);

}

}

So long as the spring-cloud-starter-eureka-server dependency is present in the Maven / Gradle build config, this will start the application as a Eureka server. The starter dependency is part of the Spring Cloud project so you’ll want to use the latest Spring Cloud release train (currently Brixton.SR5) to manage your Maven dependency versions:

Some basic configuration is required in the application.properties (or application.yml) file:

YAML

1

2

3

4

5

# Not a client, don't register with yourself

eureka.client.registerWithEureka: false

eureka.client.fetchRegistry: false

server.port=8761

When this Eureka server starts, it will listen for registrations on port 8761. When our microservices start, they’ll make a call to Eureka to register themselves. Then they can query Eureka to find other registered servers. Eureka also provides a simple status console which can be viewed on http://localhost:8761.

This console shows that Eureka is running and that no instances are currently registered.

Registering services with Eureka

Now that we have a centralized discovery server, we need every service to register with it. This is about as easy as creating the server. First, we need to add the
spring-cloud-starter-eureka dependency to Maven / Gradle. Again, use the spring-cloud release train to manage versions:

XHTML

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

<dependencies>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-eureka</artifactId>

</dependency>

</dependencies>

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-dependencies</artifactId>

<version>Brixton.SR5</version>

<type>pom</type>

<scope>import</scope>

</dependency>

</dependencies>

</dependencyManagement>

Then, enable discovery with the
@EnableDiscoveryClient annotation on a
@Configuration class or the
@SpringBootApplication entry point class:

Java

1

2

3

4

5

6

@Configuration

@EnableDiscoveryClient

publicclassRestConfig{

// Application beans configured here

}

And finally, add a couple of configuration settings to the application.properties (or application.yml) config file. This tells the application where Eureka is and how this service should be named in Eureka:

1

2

3

eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/

spring.application.name=spanners-api

Now, when we start the spanners-api service, we can see it registered in Eureka:

Querying Eureka

In my application, our front end component (spanners-mvc) depends on two back end microservices (spanners-api and spanners-users). Instead of hard coding the locations of the two microservices in our front end component, we want it to ask Eureka. To do this we first follow the steps above to register the spanners-mvc component with Eureka. Just to check this has worked, we can look at the Eureka console to confirm that spanners-mvc and the two microservices are all registered:

Now, we can refer to the back end microservices by using their names rather than their server addresses. The current examples from Spring suggests something like this:

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

@Service

publicclassWebAccountsService{

@Autowired

@LoadBalanced

protectedRestTemplate restTemplate;

protectedStringserviceUrl="http://ACCOUNTS-SERVICE";// ACCOUNTS-SERVICE is the name of the microservice we're calling

publicAccount getByNumber(StringaccountNumber){

Account account=restTemplate.getForObject(serviceUrl

+"/accounts/{number}",Account.class,accountNumber);

if(account==null)

thrownewAccountNotFoundException(accountNumber);

else

returnaccount;

}

...

}

The
@LoadBalanced annotated
RestTemplate will resolve application names (ACCOUNTS-SERVICE) to a real server name / port by querying Eureka. The
@LoadBalanced annotation tells Spring Boot to customize the
RestTemplate with a
ClientHttpRequestFactory that does a Eureka lookup before making the HTTP call. To make this work, you’ll need to add a new config setting to application.properties:

1

ribbon.http.client.enabled=true

This just switches on the Ribbon load balancing behind the
@LoadBalanced annotation.

Eureka with Spring Boot 1.4 RestTemplateBuilder

As of Spring Boot 1.4, it’s no longer recommended to directly
@Autowire an instance of
RestTemplate into a Rest client class. Instead, we can use the
RestTemplateBuilder to give us some more flexibility in configuring the
RestTemplate. It also allows us to use the new @RestClientTest annotation to test Rest clients. More details on the advantages of the new
RestTemplateBuilder in my previous post on the subject.

If we don’t
@Autowire a
RestTemplate bean though, we can’t use the
@LoadBalanced annotation to customize the
RestTemplate for Eureka lookups. At the time of writing, Spring has no built in solution for this as the current Spring Cloud release train (Brixton) was built for Spring Boot 1.3 – without
RestTemplateBuilder support. If you want to use the
RestTemplateBuilder with Eureka, you’ll need to customize the
RestTemplate yourself. This is very straightforward:

* Customize the RestTemplate to use Ribbon load balancer to resolve service endpoints

*/

@Bean

publicRestTemplateCustomizer ribbonClientRestTemplateCustomizer(

finalRibbonClientHttpRequestFactory ribbonClientHttpRequestFactory){

returnnewRestTemplateCustomizer(){

@Override

publicvoidcustomize(RestTemplate restTemplate){

restTemplate.setRequestFactory(ribbonClientHttpRequestFactory);

}

};

}

}

This is pretty much a copy of the RibbonAutoConfiguration.RibbonClientConfig bean used to power the
@LoadBalanced annotation except that it configures an instance of
RestTemplateCustomizer. The
RestTemplateBuilder automatically pulls in all configured
RestTemplateCustomizers when it initializes so we don’t need to manually inject this into anything.

The conditional annotations on this configuration class create the
RestTemplateCustomizer only if Ribbon (and Eureka) is enabled.

With this bean present, we can use the
RestTemplateBuilder in our Rest client code and it will resolve our application names, just as if we had use the
@LoadBalanced annotation.

However, you do go on to mention how instead you can use RestTemplateBuilder. Instead of doing that, why not just do what the spring docs recommend, and do something like this in a @Configuration class?

The disadvantage though is that you can’t (yet) just stick a @LoadBalanced annotation on it and expect it to work with Eureka. So if you don’t need to customize your builder and are happy to test without the nice @RestClientTest stuff introduced in Spring Boot 1.4, you are indeed best sticking with a simple @LoadBalanced RestTemplate.

Hi Stuart,
I am new to this microservices and eureka configuration.
Can you please help me by sharing some sample code or link from where i can get understanding reference for creating structure with spring boot and eureka without docker.
As even i am newer to docker.
But for now as per the requirement i need to create a structure with spring boot fusing microservices and eureka.
Please help me.It would be really great if you give some solution.

I have one question. When we have more than one Eureka server instance running for scalability and failover reasons, how will the client make a lookup to the Eureka via the Resttemplate.

Since there are more than one Eureka Server instances how does the client decide which one. Does Ribbon does the load balancing for that too similar to the way it does for target service being consumed?

I would expect that you’d want to protect your Eureka server at the network / firewall level. If you’re on a traditional LAN, you’d put it on an internal (not internet facing) server. If you’re in a cloud infrastructure such as AWS, you’d put it on an internal security group.

If you need this to be on a server exposed to the outside world, you may be able to use Spring Security to restrict access. If you’re using Spring Boot, add the spring-boot-starter-security starter and you can then use all the Spring Security features. You could restrict the status page using a simple username / password or you could restrict by other means – for example by IP address.

If i want to do Integration Testing of The Controller present in your Account-Service using @SpringBootTest ,then is there is need of registration of Account-Service to Discovery Server for Integration Testing ??