Spring Cloud with Netflix Eureka Server
In this tutorial we will be implementing Microservices architecture using spring cloud Netflix Eureka Server.An Enterprise Application consist of a number of microservices. As the number of microservices in the aplication increase, the system becomes complex for the communication between them.
So there comes the need to store the addresses of all the service present with their port numbers.This is where Spring Cloud Eureka Server comes into existence.
Eureka Server is therefore also known as Discovery Server and the registered Services ae known as Eureka Client or Discovery Client.
Creating a project which includes the use of Eureka Server is similar like that of implementation of Microservices architecture. The main components required for building large microservices architecture applications includes the following:-
Eureka which is a service discovery
Ribbon which is responsible for load balancing
hysterix which is responsible for circuit breaker Zuul which is responsible for effective routing.
-
The microservices architecture of Eureka Server and Eureka client can be represented by the following diagram:-
In this example, I would be creating two different services called employee service and the organisation service , both connected with a common medium known as Eureka Server.
Eureka Server
Eureka Server acts as a Disvcovery Server where all the other microservices register themselves for smooth communication.
Whenever two different microservices wants to communicate with each other, it is important for them to connect with Eureka Server firstly.
The project structure for Eureka Server can be defined as follows-
We need to start by creating a Maven pom.xml(Project Object Model) file. The pom.xml file contains the project configuration details.<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.codeusingjava</groupId> <artifactId>EurekaServer</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>EurekaServer</name> <description>Spring cloud with Netflix Eureka Project</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Creating configuration in application.yml as follows-server: port: ${PORT:8761} eureka: client: registerWithEureka: false fetchRegistry: false server: waitTimeInMsWhenSyncEmpty: 0
Creating another configuration file known as bootstrap.yml as follows-
bootsrap.yml file loads before the application.yml. It consist of the properties which make the configuration server ready.On the other hand, the application.yml contains the properties specific to that of applications.spring: application: name: eureka
The main class for EurekaServer is as follows:-
@EnableEurekaServer specifies that the application acts as a Eureka Server.package com.codeusingjava.eurekaserver; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @EnableEurekaServer @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
Client Configuration
We have two client microservices which will register to the Eureka Server- Employee Microservice and Organization Microservice. Both the microservices will communicate with each other with the help of Eureka Server.Employee Microservice
The project structure for the employee microservice is as follows-
The pom.xml for eureka client service is as follows:-
Spring boot starter actuator dependency provides us with a number of endpoints by which application can be monitored effectively.<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.howtodoinjava</groupId> <artifactId>spring-eureka-client-student-service</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>EurekaClientEmpService</name> <description>Spring cloud with Netflix Eureka</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
The application.yml in the employee microservice is as follows:-server: port: 9001 eureka: instance: leaseRenewalIntervalInSeconds: 1 leaseExpirationDurationInSeconds: 2 client: serviceUrl: defaultZone: http://127.0.0.1:8761/eureka/ spring: application: name: employee-service management: security: enabled: false logging: level: com.codeusingjava: DEBUG
It contains some of the important properties of an employeepackage com.codeusingjava.eurekaclientempservice.model; public class Employee { private String name; private String designation; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDesignation() { return designation; } public void setDesignation(String designation) { this.designation = designation; } public Employee() { super(); // TODO Auto-generated constructor stub } public Employee(String name, String designation) { super(); this.name = name; this.designation = designation; } }
Creating the helper class in the employee service.
Whenever the service gets registered successfully to the Eureka Server, the following method customise the actuators info method. By this way, the info endpoint of our actuators can be represented in an effective manner.package com.codeusingjava.eurekaclientempservice.helper; import java.util.Collections; import org.springframework.boot.actuate.info.Info; import org.springframework.boot.actuate.info.InfoContributor; import org.springframework.stereotype.Component; @Component public class EurekaClientEmpServiceContributor implements InfoContributor { @Override public void contribute(Info.Builder builder) { builder.withDetail("details", Collections.singletonMap("description", " It is Employee service,which is dicovery server aware!!! We can call this service by Org Microservice, which is again dicovery server aware!!! ")); } }
It contains the url that can be accessed by other microservices too.package com.codeusingjava.eurekaclientempservice.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.codeusingjava.eurekaclientempservice.model.Employee; @RestController public class EmployeeServiceController { private static Map<String, List<Employee>> company = new HashMap<String, List<Employee>>(); static { company = new HashMap<String, List<Employee>>(); List<Employee> record = new ArrayList<Employee>(); Employee e1 = new Employee("Rajesh Gopinathan", "CEO"); record.add(e1); Employee e2 = new Employee("Nataraj Chandrashekharan", "Chairperson"); record.add(e2); Employee e3 = new Employee("Samir Sekaria", "CFO"); record.add(e3); company.put("Tata Consultancy Services", record); record = new ArrayList<Employee>(); e1 = new Employee("Salil Parekh", "CEO"); record.add(e1); e2 = new Employee("NR Narayan Murthy", "Chairperson"); record.add(e2); e3 = new Employee("Nilanjan Roy", "CFO"); record.add(e3); company.put("INFOSYS", record); } @RequestMapping(value = "/getEmployeeDetails/{companyname}", method = RequestMethod.GET) public List<Employee> getEmployees(@PathVariable String companyname) { System.out.println("Getting Employee details for " + companyname); List<Employee> empList = company.get(companyname); if (empList == null) { empList = new ArrayList<Employee>(); Employee std = new Employee("Not Found", "N/A"); empList.add(std); } return empList; } }
The main class for the eurekaclientempservice is as follows:-
@EnableEurekaClient specifies that the the application is a Eureka client.package com.codeusingjava.eurekaclientempservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class EurekaClientEmpServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientEmpServiceApplication.class, args); } }
Organisation Microservice
It is a microservice which contains details of the organisatuion registered. We can also get the employee details of a particular organisation by this microservice.
The pom.xml for eureka client service is as follows:-<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.howtodoinjava</groupId> <artifactId>spring-eureka-client-school-service</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>Eureka-org-service</name> <description>Spring cloud with Netflix Eureka</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.4.RELEASE</version> <relativePath/> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-rest</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
The application.yml in the organisation microservice is as follows:-server: port: 9000 eureka: instance: leaseRenewalIntervalInSeconds: 1 leaseExpirationDurationInSeconds: 2 client: serviceUrl: defaultZone: http://127.0.0.1:8761/eureka/ spring: application: name: Organisation-service management: security: enabled: false logging: level: com.codeusingjava: DEBUG
The restTemplate is used for creating RESTful web applications. The exchange() method in the restTemplate effectively fulfills the web services for all http methods.package com.codeusingjava.eurekaclientorgservice.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController public class OrgServiceController { @Autowired RestTemplate restTemplate; @RequestMapping(value = "/getOrgDetails/{companyname}", method = RequestMethod.GET) public String getStudents(@PathVariable String companyname) { System.out.println("Getting School details for " + companyname); String response = restTemplate.exchange("http://employee-service/getEmployeeDetails/{companyname}", HttpMethod.GET, null, new ParameterizedTypeReference
Run the following Spring Boot class for starting our application. This class contains the main method for the Organisation-service.() { }, companyname).getBody(); System.out.println("Response Received as " + response); return "Company Name - " + companyname + " \n\n Employee Details " + response; } @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
@EnableEurekaClient annotation shows that the application acts as a eureka client.package com.codeusingjava.eurekaclientorgservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication @EnableEurekaClient public class EurekaClientOrgServiceApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientOrgServiceApplication.class, args); } }
Run the applications
First we need to run the eureka server as Spring boot Application. Then we need to run both the Eureka Client as Spring Boot Application.
The output can be displayed as follows:-
If we click on the url of Employee Services. The customised info is shown by the helper class.
We can see that the employee details can also be fetched successfully after registering both the services on Eureka Server.
Downloads-
Spring Cloud + Eureka Hello World Example