- What are the various components And principles of micro service architecture?
- A micro-service architecture is based on following components and principles
- Solid principles
- These principles provide scalability to the micro services.
- These include single chain responsibility principle, Open close principal, Liskov substitution, Interface segregation, Dependency inversion.
- A micro service should follow API Gateway configuration pattern like zuul.
- A Micro service Should have a logging mechanism Using event, based logging like Kafka,Sluth,Zipkins,Grafna.
- A Micro service Should have a service discovery, client like Eureka server.
- Approach for synchronous and asynchronous communication.
- REST Template
- HTTP client API
- FEIGN RETRIVAL
- KAFKA OR ANY MESSAGE BROKER FOR NON-SYNCHRONOUS COMMUNICATION.
- Layers in a Java application/Microservice/Module.
- Data access layer
- Data access layer is independent layer responsible for performing the CRUD operations against a data store.
- Services provided by their Data Access Layer are used by the Services layer. This is where our business logic or application logic resides.
- Use Spring Data
- uses JDBC/ORM technology to interact with Database
- Presentation layer
- The presentation layer is responsible for generating the user interface.
- Uses Model View Controller for interacting with client app.
- Services layer
- Services provided by service layer are used by presentation layer classes and Interfaces.
- Utility layer
- Spring email
- Java Mail Sender
- Email Configuration
- 3rd party libraries
- Generate reports
- Jfree charts
- Integration layer
- The integration layer allows our application to access other applications in the organization or vice versa.
- Integration layer is made up of web services.
- Restful web services layer.
- Test using postman.
- Uses webservices to interact with other apps.
- The classes and interfaces which constitute these layers are as follows
- Data Access Layer
- Components
- Model class(C)
- Represents our Domain Model.
- It's a common class used across all layers.
- Generally these classes are compiled in jars and stored in common artifactory. Build management tools then pull these classes in different services and keep a check that latest stable version is available with all the services.
- It does not fall under any of the layers in particular just represents a wrapper to database entities.
- Name of the class is derived from Module Name.
- Represents data of our domain.
- Represents a Wrapper for a database table.
- Data Access Layer Interface(IDAO(I))
- Once we have model class we create the Data Access Layer Interface.
- This interface maybe different for different entities.
- This interface acts as a contract between database and our application.
- We define all the CRUD operations in these interfaces.
- Once we code to interfaces we implement them in DAO implementation classes.
- Generally named as I{ModuleName}DAO.
- Implemented by {ModuleName}DAOImpl class.
- Carries a "Is-A" relation with interface.
- Creating Data Access Layer
- Module Student
- We create a model class with name student.
- This model acts as a wrapper class for entity.
- Student Repository extends Spring Data JPA Repository
- Wrapper for operations on Student entity.
- Service Layer
- IService(I)
- Once we have the Data Access Layer class we create the service layer interface which acts as the contract of operations with Data Access Layer.
- I{ModuleName} Service Interface.
- Service Implementation Class(C)
- Next we have service implementation class where these operations are implemented.
- It uses services provided by DAO Interface.
- {ModuleName}ServiceImpl class
- IS-A relationship with Interface
- Uses services provided by Data Access Layer Interface.
- Carries a "Has-A" relationship with IDAO Interface.
- Controller class
- Responsible for generating the UI.
- Controller uses services from services layer.
- Independent Utility classes(C)
- Responsible for performing operations across the layers.
- Independent Validator Classes(C)
- We create these classes to validate the data that comes in from user and goes back to the user.
- Integration Layer
- Service Provider(SP) or Service Consumer(SC)
- These are web services.
- Our application can be a service provider to downstream systems or service consumer from upstream systems or can be both.
- View(C)
- For representing the data as excel sheet, PDF or any other special view.
- Presentation Layer
- Controller
- Has a naming convention like {ModuleName}Controller.
- Carries a "Has-A" relationship with Service Layer Interface.
- Non Functional Application Requirements.
- Security
- Logging
- Deployment
- Spring cloud libraries are used to build microsrvices in Java Spring Framework.
- We can easily build microservices design patterns with Spring Cloud.
- Helps to run microservices in a dockerized environment.
- Netflix technologies developed most of the Spring Cloud Libraries.
- Spring Cloud Projects
- Service Discovery
- Fault Tolerance
- Configuration
- Authorization
- In Monolithic applications all modules are placed in one single application, overtime as application grows it will be a huge code base.
- Fixing defects is difficult.
- After fixing defects we have to deploy the entire application.
- When adding new features other modules should not get impacted as application is coupled.
- Entire application is mostly coded in one single technology.
- Advantages of using Microservices.
- Simplicity
- Since we are putting up code into multiple layers. The application becomes simple and easy to understand.
- Separation of concerns.
- Each layer classes are concerned about their functionality only.
- Easy maintenance
- We can analyze issue by just looking at the layer.
- Micro services Architecture organizes components in such an order that they are completely loosely coupled and have their own database.
- Micro services are small and focused to a functionality.
- All modules are scattered along different micro services.
- Each microservice has its own database or set of tables.
- Microservices are autonomous.
- Each microservice is packed to its own server.
- The communication between micro services happens through network calls.
- Each microservice exposes an API which is consumed by other micro services.
- These API's are REST API's.
- Micro services are heterogeneous that is each one of them can be written in a separate language like Java, Python , .Net or node JS and can be hosted by a separate environment.
- We can migrate micro services to a new better technology independently without impacting other microservices.
- If one component fails other keeps working in our system which prevails Robustness.
- We should be able to change and deploy our applications without changing impacting other services.
- As our user base grows our application should be able to scale Monolithic app requires entire application to be deployed to multiple servers although load is only on few modules in our application.
- In micro services only concerned modules/services can be scaled thus entire application need not be scaled.
- A microservice can be reused by other micro services. If we have a better service available for a module we can simply replace that service instead of integrating it in the application.
- As we have seen in Rest Templates sections we were hard coding url's of different components which is not a good approach.
- Multiple services may be working with multiple instances so hard coding of urls as done in REST Templates may not be very scalable and Manageable.
- A service may go down based on which we must handle a service programmatically whether its running or not.
- Services can register themselves at a central server and de-register when not available.
- With service discovery we can do monitor and do health check on services and remove unhealthy instances.
- Spring Cloud Netflix is popular project which can be used to implement service discovery using Spring Cloud using
- Spring Cloud Netflix Eureka Server
- Spring Cloud Eureka Client
- We have a discovery server and we register services on that server.
- Discovery server acts as a registry for services and manages the services.
- It knows when the services are up, when they are down.
- We can look up services with a certain id or name.
- Create a project from start.spring.io with following dependencies.
- Eureka Server
- In the main class add annotations @EnableEurekaServer
- Change the default to something which the client are not using server.port property in properties file.
- Give the app a name using parameter spring.application.name property in properties file.
- Set eureka.client.register-with-eureka=false.
- We do not want the server to register with itself
- Set eureka.client.fetch-registry=false
package com.springimplant.eurekaserver;
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);
}
}
Spring Boot Properties File
server.port=8761
spring.application.name=springimplant-discovery-server
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
Registering Service with Server
- Add Eureka Discovery Client web-service as dependency.
- Add annotation @EnableEurekaClient to the main class of the application.
- Give the service a name using property spring.application.name
- Give a new port to service
package com.springimplant.cms;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class CmsApplication {
public static void main(String[] args) {
SpringApplication.run(CmsApplication.class, args);
}
}
spring.jpa.database-platform=org.hibernate.dialect.SQLiteDialect
spring.jpa.hibernate.ddl-auto=none
spring.jpa.show-sql=true
spring.datasource.url=jdbc:sqlite:cms.db
spring.datasource.username=
spring.datasource.password=
spring.datasource.driver-class-name=org.sqlite.JDBC
spring.application.name=springimplant-course-api
server.port=8001
Discovering a Service Registered on Server
- We will let our server discover another service(Service 1) and using this service(Service 1) discover a service(Service 2) already registered on server and use it.
- Add Eureka Discovery Client web-service as dependency.
- So Registering a service and making a service discover-able are 2 different aspects.
- Add annotation @EnableEurekaClient to the main class of the service.
- Give the new port to the service using server.port
- Give the service a name using property spring.application.name.
- Set eureka.client.register_with_eureka=false.
- In controller autowire the Eureka Client object.
- In method
- Create an object of InstanceInfo as shown below using Eureka Client Object using method getNextServerFromEureka()
- The two parameters are
- service name
- type of connection(boolean) secured/unsecured
- From the InstanceInfo we can get the homepage url of service using getHomepageUrl()
- Now we can append endpoints to the url and call respective methods & get results.
spring.application.name=springimplant-coursecatalog
server.port=8002
eureka.client.register-with-eureka=false
package com.springimplant.course;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class CourseCatalougeApplication {
public static void main(String[] args) {
SpringApplication.run(CourseCatalougeApplication.class, args);
}
}
Controller File package com.springimplant.course.controller;
import java.math.BigInteger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import com.springimplant.course.core.Course;
@RestController
public class CatalogController {
@Autowired
private EurekaClient eurekaClient;
@GetMapping("/")
public String getCatalogHome() {
String courseAppMsg="";
String courseUrl="http://localhost:8080/";
RestTemplate restTemplate=new RestTemplate();
courseAppMsg=restTemplate.getForObject(courseUrl,String.class);
return("Welcome to Course Catalog "+courseAppMsg);
}
@GetMapping("/services/cataloghome")
public String getCatalogHomeService() {
String courseAppMsg="";
InstanceInfo instanceInfo=eurekaClient.getNextServerFromEureka("springimplant-course-api",false);
String courseUrl=instanceInfo.getHomePageUrl();
RestTemplate restTemplate=new RestTemplate();
courseAppMsg=restTemplate.getForObject(courseUrl,String.class);
return("Welcome to Course Catalog "+courseAppMsg);
}
@GetMapping("/catalog")
public String getCatalog() {
String courses="";
String courseUrl="http://localhost:8080/courses";
RestTemplate restTemplate=new RestTemplate();
courses=restTemplate.getForObject(courseUrl,String.class);
return("Our Courses are "+courses);
}
@GetMapping("/services/catalog")
public String getCatalogService() {
String courses="";
InstanceInfo instanceInfo=eurekaClient.getNextServerFromEureka("springimplant-course-api",false);
String courseUrl=instanceInfo.getHomePageUrl();
courseUrl+="/courses";
RestTemplate restTemplate=new RestTemplate();
courses=restTemplate.getForObject(courseUrl,String.class);
return("Our Courses are "+courses);
}
@GetMapping("/catalogcourse/{id}")
public String getCatalogCourse(@PathVariable("id") BigInteger id) {
Course course=new Course();
String courseUrl="http://localhost:8080/"+id;
RestTemplate restTemplate=new RestTemplate();
course=restTemplate.getForObject(courseUrl,Course.class);
return("Our Course is "+ course.getCoursename()+" by "+course.getAuthor());
}
@GetMapping("/services/catalogcourse/{id}")
public String getCatalogCourseService(@PathVariable("id") BigInteger id) {
Course course=new Course();
InstanceInfo instanceInfo=eurekaClient.getNextServerFromEureka("springimplant-course-api",false);
String courseUrl=instanceInfo.getHomePageUrl();
courseUrl+="/"+id;
RestTemplate restTemplate=new RestTemplate();
course=restTemplate.getForObject(courseUrl,Course.class);
return("Our Course is "+ course.getCoursename()+" by "+course.getAuthor());
}
}
Microservices Fault Tolerance
- There may be a case where a micro-service is down.We must handle it programmatically else the application may see many other web-services fallback.
- In ideal situation a microservice going down may impact several other microservices
- System Issues,Network Issues,Database Issues may cause a web-service to go down.
- A popular technique to handle failure in microservices is circuit breaker pattern
- Stop sending any further requests to the downstream service if we find the service is down.
- Spring cloud has Netflix Hystrix libraries to implement this.
- The way it works is if more than 50% of the requests fail in a 10 sec rolling window then break the circuit.
- Allow a single request every 5 sec to check if the service is up.
- To handle the failure we can have a fallback method which can call another service or which can call another method using which we can display some message to the user that service is down.
- We can also display data from a separate backup microservice.
- Add the Hystrix dependency.
- Add annotation above the main class @EnableCircuitBreaker
- Add @HystrixCommand(fallbackMethod="nameofmethod") annotation above the method which needs to do the Circuit Breaking
- Now just add the method to the controller and it will trigger whenever there is a service failure due to any reason.
package com.springimplant.course;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class CourseCatalougeApplication {
public static void main(String[] args) {
SpringApplication.run(CourseCatalougeApplication.class, args);
}
}
@GetMapping("/services/cataloghome")
@HystrixCommand(fallbackMethod = "displayDefaultHome")
public String getCatalogHomeService() {
String courseAppMsg="";
InstanceInfo instanceInfo=eurekaClient.getNextServerFromEureka("springimplant-course-api",false);
String courseUrl=instanceInfo.getHomePageUrl();
RestTemplate restTemplate=new RestTemplate();
courseAppMsg=restTemplate.getForObject(courseUrl,String.class);
return("Welcome to Course Catalog "+courseAppMsg);
}
public String displayDefaultHome()
{
return("Welcome to SpringImplant"+" Please try after sometime");
}
Externalize Configuration Properties
- Whenever we make a change in the application properties file we have to modify application properties of each service and restart the service applications.
- This will not work when our project is in production and we have the entire project in jar file.
- We should not touch jar file to modify properties file.
- Various techniques are available to externalize the configuration parameter in application.properties file.
- A popular approach is to use the Spring Cloud Config Server
- Acts as a central Repository and manages configuration files of all services.
- Manage global properties for all micro-services and manage micro services specific properties.
- Spring cloud config server is like any other Spring Boot App.It doesn't store the actual data.The data is managed in a backed repository like git.
- Spring cloud config server continuously polls the git repository or the back-end repository and keeps properties file information in memory.
- We can have a global properties file applicable to all micro-services
- We can have micro services specific properties file like order service properties or payment service properties in the git repository.
- Spring cloud server will keep a record of all the properties file available in git repository and try to map them to micro-services.
- We register a Spring Cloud Config Server on Eureka Server so that it can be discovered by other web services.
- Create a new project on start.spring.io
- Add Dependencies
- Config Server
- Eureka Discovery Client
- In main class add annotation @EnableConfigServer on top @EnableDiscoveryClient
- Give the application a port number and give it a name
- Next we will have to point this config server to a back-end git repository
- The spring cloud config server will pull the configuration from a GIT Repository and serve it to the clients.
- In this repository we will have a global configuration file and configuration file from individual web services.
- Run it and specify the endpoints to the url as /propertyfilename/default and we will get desired configuration properties which includes application properties and global properties.
- For example if your service properties file name is "springimplant-order.properties" then endpoints would be "/springimplant-order/default.
- The application properties will override the global properties.
package com.springimplant.configserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigserverApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigserverApplication.class, args);
}
}
Properties file
server.port=8888
spring.application.name=springimplant-config-server
spring.cloud.config.server.git.uri=https://github.com/gauravmatta/microservices.git
- You can check the configuration files and their history from github url as in properties file
- https://github.com/gauravmatta/microservices.git
- Though you will not be able to push in any new changes
- Add the following dependencies to the services
- REST Repositories
- Config Client
- Eureka Discovery Client
- Spring Boot Actuator
- Project used to monitor the health of the application.
- Used to Refresh Properties File at runtime.
- We are creating a service over here with these four dependencies
- We will add some properties to the property file.
- To read values from the property file we use @Value annotation in controller as follows.
package com.springimplant.orderapi.controllers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class OrderController {
@Value(("${organization.name}"))
private String organizationName;
@Value(("${service.welcome.message}"))
private String serviceMessage;
@GetMapping("/")
public String getOrder()
{
return(organizationName+"***"+serviceMessage);
}
}
Properties File
Integrating Micro-services with Spring Cloud Config Server using Eureka Server
server.port=8003
organization.name=Spring Implant Application
service.welcome.message=Welcome to Order Service from internal properties
Integrating Micro-services with Spring Cloud Config Server using Eureka Server
- Create 2 services and add @EnableDiscoveryClient to the main file of the services.
- We have created order and payment services here.
- Now Run these 2 services in collaboration with cloud config server using Eureka Server.
- So basically we will have 3 services and 1 server started now at 4 different ports
- Cloud Config Sevice
- Payment API Service
- Order API service
- Eureka Server
- Global properties will be fetched from the git repository automatically.
- We find that now the application shows properties from the Global properties file from the Git repository and not the local properties file automatically.
- This is managed by the Spring Cloud Config Server automatically.
- Next we must name these services in their local properties file in accordance with the properties file on git repository.
- The properties file name in the git repository must match with the name of the property spring.application.name in local properties file of service that is how this synchronization works.
- Spring Cloud Config Server will map the "springimplant-payment-service" name of service to the "springimplant-payment-service.properties" file on the repository and will treat it as its local properties file.
- Now whenever we make any changes to the properties file in the git repository we find that it is picked immediately by the config server but when we look into services we need restart them to see the impact.
- So now our properties are centralized next is how we can apply them to services without having to restart them.
server.port=8006
spring.application.name=springimplant-payment-service
organization.name=Spring Implant Application
service.welcome.message=Welcome to Payment Service from internal properties
Order Services Properties File
server.port=8003
spring.application.name=springimplant-order-service
organization.name=Spring Implant Application
service.welcome.message=Welcome to Order Service from internal properties
Git Repo:
Refreshing Configuration without restarting Micro-services
- Spring actuator provides an endpoint or url using which we can refresh the changes in properties file.
- We need to expose the endpoints using property management.endpoints.web.exposure.include=*
- Here * exposes all the endpoints we can also expose specific endpoints.
- Add @RefreshScope annotation to the Controller/Bean which we want to refresh at run time.
- We are using Spring actuator dependency to achieve this.
- To check the health of the service using actuator use endpoints "/actuator/health" as GET request.
- We add these endpoints to the service and not to the Spring Cloud Config Server.
- To refresh we need to send a post request with empty body to endpoint "/actuator/refresh"
- It will return what changed properties are.
- We can use Postman tool to send this request
- We can automate this i.e. whenever we are pushing file to repository the "/actuator/refresh" endpoint will be invoked and changes will get reflected
server.port=8006
spring.application.name=springimplant-payment-service
organization.name=Spring Implant Application
service.welcome.message=Welcome to Payment Service from internal properties
management.endpoints.web.exposure.include=*
Controller
package com.springimplant.paymentapi.controllers;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RefreshScope
public class PaymentController {
@Value(("${organization.name}"))
private String organizationName;
@Value(("${service.welcome.message}"))
private String serviceMessage;
@GetMapping("/")
public String getOrder()
{
return(organizationName+"***"+serviceMessage);
}
}
Snapshots from PostMan Tool
Dynamic Routing using Netflix Zuul
Client Side Load Balancing using Netflix Ribbon
- Anyone who wants to access micro-services needs to know the exact url and exact port.
- We need to tell the clients exact url and port in order to use the micro services
- This scenario may not be good when we have many microservices running in an application on different machines and ports.
- A solution to this is API gateway or gateway service.
- This acts as a single point of entry for all clients and the gateway service can go and get the exact url and port of the micro-service from the discovery server and serve it to the enduser.
- The enduser or the clients need not know the exact url and ports. Gateway service can manage all the request routing.
- Gateway service also takes care of other functionality like
- Authentication-ensure that only legitimate requests are reaching the microservice.
- Log the incoming requests for auditing purpose
- Enhance the request and add additional information which can be consumed by micro-services.
- Acts as a load balancer.
- Invoke different api's for different clients for example
- Desktop requests are served by one microservice
- Mobile Device requests are served by another microservice.
- Netflix Zuul is used to implement Gateway service
- We already have payment and order services we will use these.
- Next we already have eureka server running we will use it.
- Create a project called as "gateway service" with following dependencies
- Eureka Discovery Client
- Zuul
- In the main class file add the following annotations
- @EnableEurekaClient/@EnableDiscoveryClient
- @EnableZuulProxy
- In the properties file give it a name default port will be 8080
- Now using the url of this server and with endpoints as service names of order and payment we can access the service directly from one port which routes to the other ports.
- With the gateway service url we are able to access both the microservices
- This is dynamic routing implemented via Netflix Zuul Project.
Gateway Service Main file
package com.springimplant.gatewayservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class GatewayserviceApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayserviceApplication.class, args);
}
}
Client Side Load Balancing using Netflix Ribbon
- We may have microservices which is accessed by multiple other external applications or services.
- This increases the load on the service which may result in delayed response or timeout for many requests.
- To resolve this one way is to create multiple instances of the same service at different ports.
- We can add a load balancer which will route the requests to different instances of the service depending on which one is available or work in a round robin fashion.
- This is server side load balancing where there is an additional hardware involved also there is additional network hop.
- All the outside clients will first target load balancer and load balancer will target the application which will host microservice.
- Another way is to perform load balancing at client side.
- In this model there is no intermediate load balancer server.
- Client knows the number of instances available for a load balancer service and decides which one to invoke based on a round robin fashion or certain logic.
- This is handled via programming and no additional hardware is involved.
- We implement Client Side Load Balancing using Spring Cloud Netflix ribbon library
- Netflix ribbon has built in software to do the load balancing.
- Spring Rest Templates has the required integration for Netflix Ribbon.
- Rest Templates can balance requests across multiple instances of a service using the ribbon load balancer client.
- Netflix Ribbon can work with or without Eureka Server
- By default the algorithm works on a round robin fashion to distribute load.
- Create a generic REST microservice which is a Eureka Client and is discoverable on Eureka Server.
- Let us call it currency microservice which can serve as an example of most used microservice.
- Next we are creating a Controller which will return Port number as response.
- This way we can check from which port of current instance we are receiving data.
- Port is a property defined in property file of Spring Boot and we have seen earlier how we can fetch these in controller.
- Give this app a name.
- Allow parallel run of the instances of this service in IDE
- In Eclipse IDE just change the port and run the service again
- Next we will create an app which will use these services
- Add Ribbon Dependency to this.
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency>
- We will use CourseCatalouge app here to consume this webservice which we have created earlier.
- We will Autowire RestTemplate generate its getters and setters
- Autowire instance of EurekaClient so the we can fetch the node and homepage url of our service as shown.
- On the Getter of the RestTemplate add @Bean annotation and add @LoadBalanced annotation
- @LoadBalanced annotation will help to connect with the Ribbon Client.
- REST Templates can balance requests across multiple instances of a service using the Ribbon Load Balancer client to implement client side load balancing.
package com.springimplant.course.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
@RestController
@RequestMapping("/currency")
public class CurrencyController {
@Autowired
private EurekaClient eurekaClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/")
public String getCatalogService() {
String currency="";
InstanceInfo instanceInfo=eurekaClient.getNextServerFromEureka("springimplant-currency-service",false);
String currencyUrl=instanceInfo.getHomePageUrl();
currency=restTemplate.getForObject(currencyUrl,String.class);
return("Currency value is coming from port "+currency);
}
@Bean
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
}
Debugging Microservices using Dead Letter Queue
- We will use Rabbit MQ dead letter configuration to queue messages and then integrate it with spring MVC project.
- Create two exchanges in rabbit MQ one “Myexchange1” and other for dead letter queue “dlx1”.
- Both of type topic and durable.
- Create 2 queues one a “myqueue1” Which has following arguments which are of type classic and durable.
- Dead letter exchange value as dlx1(our dead letter exchange).
- Dead letter routing key value as dlx.timeout.test1
- Message TTL value as 20,000.
- Other as DLQ1 type classic and no arguments.
- Open Myexchange1 and bind to myqueue1 with routing key as test.#
- Bind DLX1 exchange To DLQ1 with routing key as dlx.#
- Try publishing a message from Myexchange1 with routing as test.test1 wait for 20 seconds and don’t get it it will go in DLQ1 because of timeout.
- Java Code to Perform Above action is at springmvc/rabbitmq-deadletter-queue at master · gauravmatta/springmvc (github.com)
No comments:
Post a Comment