Hello Friends hope you all are doing well. Today I am going to discuss about a very hot topic now a days -Microservice. Let's look into this.
Before moving to Microservice Architecture ,we will discuss regarding Monolithic Architecture.
In Monolithic Architecture we have a single deployable unit ,frequent changes in business needs lead to do deployment of application as a whole in order to make functionality work.
There are several pitfalls of monolithic architecture which are addressed by Microservice Architecture:
Agility : frequent changes in business needs hamper agility .even with small changes entire application need to be repacked and assembled at the cost of reducing agility.
Scalability : Let's take a example of Shopping cart.there are various customer's for which unit has to be changed to incorporate a new customer there by reducing scalability of entire application.
Dev-ops Cycle : as there is a single deployable unit,even small change lead to deploy whole application again .there by increasing effort time.
To address all this issues ,Microservice Architecture comes into picture where as modules are deployed as individual components .below is the Monolithic VS Microservice architecture.
below is the microservice eco system drawn for shopping cart service:
I am going to achieve Microservice Architecture using Spring boot and Spring Cloud module.
Technology stack is being used:
1) Spring Boot 1.4.1 Release
2) Spring Cloud
3) Spring 4.0
4) Spring JDBC
5) Maven 4.0
6) JDK 1.7
Spring Cloud has predefined list of components which will be used to address issues that we face in Monolithic architecture.I am going to use below Components for this application:
(1)Netflix Eureka - Service Registration /Service Discovery,
(2) Hystrix - For Load Balancing/Fault tolerance
(3) Zuul - act as a API gateway ,request will be routed through ZUUL.
localhost Port of each service as given below:
in this example ,I am going to expose one Rest End Point which will act as a producer and another will act as a consumer which will retrieve college details of particular student from Producer Microservice.
Project Structure of each micro service is as given below :
Below is the code given :
Eureka Registry :
EurekaServerApplication.java
application.prerties:
pom.xml :
Before moving to Microservice Architecture ,we will discuss regarding Monolithic Architecture.
In Monolithic Architecture we have a single deployable unit ,frequent changes in business needs lead to do deployment of application as a whole in order to make functionality work.
There are several pitfalls of monolithic architecture which are addressed by Microservice Architecture:
Agility : frequent changes in business needs hamper agility .even with small changes entire application need to be repacked and assembled at the cost of reducing agility.
Scalability : Let's take a example of Shopping cart.there are various customer's for which unit has to be changed to incorporate a new customer there by reducing scalability of entire application.
Dev-ops Cycle : as there is a single deployable unit,even small change lead to deploy whole application again .there by increasing effort time.
To address all this issues ,Microservice Architecture comes into picture where as modules are deployed as individual components .below is the Monolithic VS Microservice architecture.
below is the microservice eco system drawn for shopping cart service:
I am going to achieve Microservice Architecture using Spring boot and Spring Cloud module.
Technology stack is being used:
1) Spring Boot 1.4.1 Release
2) Spring Cloud
3) Spring 4.0
4) Spring JDBC
5) Maven 4.0
6) JDK 1.7
Spring Cloud has predefined list of components which will be used to address issues that we face in Monolithic architecture.I am going to use below Components for this application:
(1)Netflix Eureka - Service Registration /Service Discovery,
(2) Hystrix - For Load Balancing/Fault tolerance
(3) Zuul - act as a API gateway ,request will be routed through ZUUL.
localhost Port of each service as given below:
components | Port | |
Eureka registry | 8111 | |
Producer | 8112 | |
Consumer | 8113 | |
zuul api gateway | 8114 |
Project Structure of each micro service is as given below :
Below is the code given :
Eureka Registry :
EurekaServerApplication.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | package org.main; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } } |
application.prerties:
1 2 3 4 5 |
spring.application.name=eureka-server server.port=8111 eureka.client.serviceUrl.defaultZone=http://localhost:8111/eureka eureka.client.registerWithEureka=true eureka.client.fetchRegistry=false |
pom.xml :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | <?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>org.server</groupId> <artifactId>eureka-server</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>eureka-server</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.2.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> --> </properties> <dependencies> <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>de.codecentric</groupId> <artifactId>spring-boot-admin-starter-client</artifactId> <version>1.5.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</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> |
Producer Microservice is as given below :
Model Class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package com.example.hystrix.model; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Student implements Serializable { /** * */ private static final long serialVersionUID = 1L; @Id @GeneratedValue private String id; @Column private String name; @Column private String college; public Student() { } public Student(String id ,String name,String college) { this.id = id ; this.name = name ; this.college = college; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getCollege() { return college; } public void setCollege(String college) { this.college = college; } } |
Controller :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | package com.example.hystrix.springhystrixstudentservice.controller; import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; 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.example.hystrix.model.Student; import com.example.hystrix.springhystrixstudentservice.dao.StudentDAOImpl; @RestController public class StudentServiceController { @Autowired StudentDAOImpl dao; @RequestMapping(value = "/getStudentDetailsForSchool/{college}", method = RequestMethod.GET) public List<Student> getStudents(@PathVariable String college) { System.out.println("Getting Student details for " + college); List<Student> studentList = dao.getStudent(college); System.out.println("size: " + studentList.size()); if (studentList == null) { studentList = new ArrayList<Student>(); Student std = new Student("Not Found", "N/A","N/A"); studentList.add(std); } return studentList; } } |
Data Access Layer is as given below :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | package com.example.hystrix.springhystrixstudentservice.dao; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.example.hystrix.model.Student; @Repository public class StudentDAOImpl { @Autowired public JdbcTemplate template; public List<Student> getStudent(String college) { String sql = "select * FROM student where college=?"; System.out.println("college from dao" +college); List<Student> listStudent = new ArrayList<Student>(); List<Map<String, Object>> rows = template.queryForList(sql, new Object[]{college}); for (Map row : rows) { Student stud = new Student(); stud.setId((String)(row.get("id"))); stud.setName((String)row.get("name")); stud.setCollege((String)row.get("college")); listStudent.add(stud); } return listStudent; } } |
Spring boot main class as given below :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package com.example.hystrix.springhystrixstudentservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; //@EnableDiscoveryClient @EnableEurekaClient @SpringBootApplication public class SpringHystrixStudentServiceApplication { public static void main(String[] args) { SpringApplication.run(SpringHystrixStudentServiceApplication.class, args); } } |
application.properties is as given below :
1 2 3 4 5 6 7 8 9 10 11 12 13 | server.port = 8112 spring.datasource.url = jdbc:mysql://localhost:3306/studentdb spring.datasource.username = root spring.datasource.password = admin!@# # Keep the connection alive if idle for a long time (needed in production) spring.datasource.testWhileIdle = true spring.datasource.validationQuery = SELECT 1 # Show or not log for each sql query spring.jpa.show-sql = true # Hibernate ddl auto (create, create-drop, update) spring.jpa.hibernate.ddl-auto = update eureka.client.serviceUrl.defaultZone=http://localhost:8111/eureka spring.application.name=student-producer |
pom.xml :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | <?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.hystrix</groupId> <artifactId>spring-hystrix-student-service</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>SpringBootHelloWorld</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.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> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</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-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.6</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR6</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> |
Consumer Microservice is as given below:
Controller:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | package com.example.hystrix.controller; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; 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.example.hystrix.service.StudentService; @RestController public class CollegeController { @Autowired StudentService service; @Autowired private DiscoveryClient discoveryClient; @RequestMapping(value = "/student/getSchoolDetails/{schoolname}", method = RequestMethod.GET) public String getStudents(@PathVariable String schoolname) { List<ServiceInstance> instances = discoveryClient .getInstances("student-zuul-service"); ServiceInstance serviceInstance = instances.get(0); String baseUrl = serviceInstance.getUri().toString(); System.out.println("URI IS :"+serviceInstance.getUri()+"base url is : "+baseUrl); baseUrl = baseUrl + "/getStudentDetailsForSchool/{college}"; return service.getStudentData(baseUrl, schoolname); } } |
Service class is as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | package com.example.hystrix.service; import java.util.Date; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.HttpMethod; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; @Service public class StudentService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "getStudentData_Fallback") public String getStudentData(String baseUrl, String college) { //http://localhost:8112/getStudentDetailsForSchool/{college} baseUrl="http://localhost:8112/getStudentDetailsForSchool/{college}"; String response = restTemplate .exchange(baseUrl , HttpMethod.GET , null , new ParameterizedTypeReference<String>() { }, college).getBody(); return "Circuit Breaker is not active for : "+ response +" at : "+ new Date(); } @SuppressWarnings("unused") private String getStudentData_Fallback(String baseUrl,String schoolname) { System.out.println("Student Service is down!!! fallback route enabled..."); return "CIRCUIT BREAKER ENABLED!!!No Response From Student Service at this moment. Service will be up soon - " + new Date(); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } } |
Spring Boot Main Application:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package com.example.hystrix; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @EnableAutoConfiguration @SpringBootApplication @EnableHystrixDashboard @EnableCircuitBreaker @EnableEurekaClient public class SpringHystrixSchoolServiceApplication { public static void main(String[] args) { SpringApplication.run(SpringHystrixSchoolServiceApplication.class, args); } } |
application.properties :
1 2 3 | server.port = 8113 spring.application.name=student-consumer eureka.client.serviceUrl.defaultZone=http://localhost:8111/eureka |
pom.xml :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?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>org.zuul</groupId> <artifactId>student-zuul-service</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>SpringBootHelloWorld</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.1.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> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-zuul</artifactId> </dependency> <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>Camden.SR6</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> |
ZUUL -API Gateway :
Controller :
Controller :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | package org.zuul; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; import org.springframework.context.annotation.Bean; import org.zuul.filter.ErrorFilter; import org.zuul.filter.PostFilter; import org.zuul.filter.PreFilter; import org.zuul.filter.RouteFilter; @SpringBootApplication @EnableDiscoveryClient @EnableZuulProxy public class SpringBootHelloWorldApplication { public static void main(String[] args) { SpringApplication.run(SpringBootHelloWorldApplication.class, args); } @Bean public PreFilter preFilter() { return new PreFilter(); } @Bean public PostFilter postFilter() { return new PostFilter(); } @Bean public ErrorFilter errorFilter() { return new ErrorFilter(); } @Bean public RouteFilter routeFilter() { return new RouteFilter(); } } |
application.properties
1 2 3 4 5 | zuul.routes.student.url=http://localhost:8112 eureka.client.serviceUrl.defaultZone=http://localhost:8111/eureka ribbon.eureka.enabled=false server.port=8114 spring.application.name=student-zuul-service |
Order in which application will run given below :
1)eureka-server
2)spring-hystrix-student-service
3)spring-student-zuul-service
4)spring-hystrix-college-service
below is the screenshot :
-> eureka registry started: Producer and Consumer microservice registered with Eureka Registry.
output returned by consumer
Hope you enjoyed article. For any query ping me on npjava90@gmail.com
its a great article on your blog. Thank you for sharing.
ReplyDeleteMicroservices training in Hyderabad
Awesome article! It is in detail and well formatted that i enjoyed reading. which inturn helped me to get new information from your blog. After reading your article I was amazed. I know that you explain it very well.
ReplyDeleteSalesforce Training in Chennai
Salesforce Online Training in Chennai
Salesforce Training in Bangalore
Salesforce Training in Hyderabad
Salesforce training in ameerpet
Salesforce Training in Pune
Salesforce Online Training
Salesforce Training