Microservices Raghu
Microservices Raghu
Monolithic Application: - A Project which holds all modules together and converted
as one Service (one .war file).
In this case, if no. of users is getting increased, then to handle multiple request
(load) use LBS (Load Balancing Server).
But few modules need Extra load, not all. In this case other modules get memory
which is waste (no use). Hence reduces performance of server (application).
Consider Project P1 is having 2 modules M1, M2 and their runtime memories are
M1=50 MB, M2=50 MB.
Load Balancing is done using Servers looks like.
Diagram:--
In above example, M2 Module is getting less requests from Client. So, max 2
instances are may be enough. Other 2 instances (memories) are no use. It means
near 100MB memory is not used, which impacts server performance.
Nature of Microservices:
1.Every Service must be implemented using Webservices concept.
2.Each service should be independent.
3.Services should able to communicate with each other. It is also called as “Intra
Communication”.
4.Required Services must be supported for Load Balancing (i.e. one service runs in
multiple instances).
5.Every service should able to read input data (____.properties/_____.yml) from
External Configuration Server [Config Server].
6.Service communication (Chain of execution) problems should be able to solve using
CircuitBreaker [Find other possible…].
1
7.All Servers must be accessed to Single Entry known as Gateway Service [ Proxy
Gateway or API Gateway], It supports securing, metering and Routing.
Components of SOA:
a. Service Registry and Discovery [Eureka]
b. Service Provider [Webservice Provider]
c. Service Consumer [Webservice Client]
Operations:
1.Publish
2.Discover
3.Link Details of Provider
4.Query Description (Make Http Request).
5.Access Service (Http Response).
2
Implementing MicroService Application Using Spring Cloud:
Design #1 A Simple Rest WebService using Spring Boot.
StarterClass(AdminServiceProviderApplication.java)
packagecom.demo.venky;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclassAdminServiceProviderApplication {
3
publicstaticvoid main(String[] args) {
SpringApplication.run(AdminServiceProviderApplication.class, args);
System.out.println("=-=-=-Hello From AdminServiceProvider=-=-=-");
}
}
@RestController
@RequestMapping("/provider")
publicclassAdminServiceProviderController {
@GetMapping("/show")
public String showMsg() {
return"Hello Venky";
}
}
=--=-=application.properties=-=-=-=-=-
server.port=8900
4
Starterclass(AdminConsumerApplication.java)
packagecom.demo.venky;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclassAdminConsumerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(AdminConsumerApplication.class, args);
}
}
Step #4 Define Consumer (call) code (AdminConsumer.java)
packagecom.demo.venky.rest.consumer;
importorg.springframework.boot.CommandLineRunner;
importorg.springframework.http.ResponseEntity;
importorg.springframework.stereotype.Component;
importorg.springframework.web.client.RestTemplate;
@Component
publicclassAdminConsumerimplementsCommandLineRunner {
@Override
publicvoid run(String... args) throws Exception {
RestTemplatert=newRestTemplate();
ResponseEntity<String>resp=rt.getForEntity("http://localhost:8900/provider/s
how",String.class);
System.out.println(resp.getBody());
System.out.println("=-=-=-=-=-Message From Admin Consumer=-=-=-=-");
System.exit(0);
}
}
Execution flow Screen:
First Run ProviderApplication (Starter), then ConsumerApplication(Starter)
PROVIDER SCREEEN:-
5
CONSUMER SCREEN:
Step#1: Create Eureka Server:Create one Spring Boot Starter Project with
Dependencies:Eureka Server
Eureka Server Dependencies:--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server </artifactId>
</dependency>
GroupId: com.demo.venky
ArtifactId: EurekaServerApp
Version: 1.0
6
Folder Structure of Eureka Server:
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
7
#2# Provider Application:
Step #1: Create one Spring starter App with web and Eureka Discovery dependencies
<!-- web Dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka Discovery Dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
GroupId: com.demo.venky;
ArtifactId : StudentServiceProvider
Version : 1.0
Folder Structure of Eureka Discovery for Provider Application:--
8
Step #2:- Add below annotation at Starter class level @EnableEurekaClient (given by
Netflix) or @EnableDiscoveryClient (given by Spring Cloud) both are optional.
Spring Starter class:--
packagecom.demo.venky;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
publicclassStudentServiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(StudentServiceProviderApplication.class, args);
System.out.println("StudentServiceProvider");
}
}
Step #3:- In application.properties file
server.port=9800
spring.application.name=STUDENT-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
Step #4 Define one Provider Controller
packagecom.demo.venky.rest.provider;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/provider")
publicclassStudentProvider {
@GetMapping("/show")
public String showMsg() {
return"Hello From Provider";
}
}
Execution Order: (RUN Starter Classes)
1. EUREKA SEVER
2.PROVIDER APPLICATION
GOTO EUREKA Dashboard and CHECK FOR APPLICATION
CLICK ON URL and ADD /provider/showPATH
#1 Screen Short of Eureka Server Dashboard: --
9
NOTE:-- Click on URL (Venky056:STUDENT-PROVIDER:9800) then add provider
path after URI (http://venky056:9800/provider/show)
#2 Screen Short of Provider Application:--
*** Hard coding: Providing a direct value to a variable in .java file or fixed for
multiple runs.
By using RestTemplate with URL (hard coded) we can make request. But it will not
support.
a. If provider IP/PORT number gets changed
b. Load Balancing Implementation
so, we should use Dynamic Client that gets URL at runtime based on Application
name registered in “Registry and Discovery Server (Eureka)”.
DiscoveryClient is used to fetch Instance based on Application Name and we can
read URI of provider at runtime.
RestTemplate uses URI (+path = URL) and makes Request to Provider and gets
ResponseEntity which is given back to the Consumer.
Simple Web Service Example:--
10
Microservices Example:--
If one Application is moved from one Server to another server then URI gets
changed (Paths remain same).
Consumer code:--
Step#1: -- Create one Spring Starter Project using Dependencies web, Eureka
Discovery
GroupId: com.demo.venky
ArtifactId:StudentServiceConsumer
Version: 1.0
# Folder Structure of Eureka Discovery Consumer Application:--
11
Step#2:-- At Starter class level add Annotation either @EnableEurekaClient or
@EnableDiscoveryClient (both are optional)
packagecom.demo.venky;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
//@EnableEurekaClient
//(both are optional Annotations)
@EnableDiscoveryClient
publicclassStudentConsumerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(StudentConsumerApplication.class, args);
}
}
Step#3: in application. Properties file
server.port=9852
spring.application.name=STUDENT-CONSUMER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
Step #4: Define Consumer code with RestTemplate and DiscoveryClient
packagecom.demo.venky.consumer;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.cloud.client.ServiceInstance;
importorg.springframework.cloud.client.discovery.DiscoveryClient;
12
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RestController;
importorg.springframework.web.client.RestTemplate;
@RestController
publicclassStudentConsumer {
@Autowired
privateDiscoveryClientclient;
@GetMapping("/consume")
public String consumeData() {
RestTemplatert = newRestTemplate();
List<ServiceInstance>list=client.getInstances("STUDENT-
PROVIDER");
ResponseEntity<String>resp
=rt.getForEntity(list.get(0).getUri()+"/provider/show", String.class);
return"FROM CONSUMER=>" +resp.getBody();
}
}
Execution order: -
#1 Run Starter classes in order
Eureka server, Provider Application, Consumer Application
#2 Go to Eureka and client Consumer URL enter /consumer path after PORT number.
Output:
13
Declarative ReST Client : [Feign Client]
Spring cloud supports any HTTP Client to make communication between
(Microservices) Provider and Consumer.
RestTemplate is a legacy style which is used to make HTTP calls with URL and Extra
inputs.
RestTemplate with DiscoveryClient makes mask to Provider URL. It means works
based on Application Name (Service ID). Even URI gets changed it works without any
modification at consumer side.
RestTemplate combination always makes Programmer to write manual coding for
HTTP calls.
Spring Cloud has Provided one ActingClient [which behaves as Client, but not].
It means, Provide Abstraction at code level by programmer and
Implementation is done at runtime by Spring cloud.
Feign is Declarative Client, which supports generating code at runtime and proxy
Object.By using Proxy HTTP Request calls can be made.
It supports even Parameters (Path/Query…)andGlobalDataConversion (XML/JSON).
Diagram:
@GetMapping(“/path”)
//or @RequestMapping(“path”)
public <return><method>(<params>);
……..
}
Example: (Provider Code (SID: EMP-PROV))
@RestController
@RequestMapping(“/emp”)
public class EmpProvider {
@GetMapping(“/show”)
Public String findMsg () {
……
}
}
Step #1 Create one Spring Boot Starter Project for Consumer (using Feign, web,
Eureka Discovery)
GroupId:com.demo.venky
ArtifactId: StudentServiceConsumerFeign
Version: 1.0
Step #3 Use in any consumer class (HAS-A) and make method call (HTTP CALL)
package com.app.consumer;
@RestController
public class StudentConsumer {
@Autowired
private StudentFeignClient client;
@GetMapping(“/consumer”)
Public String showData () {
System.out.pritln(client.getClass().getName());
Return “CONSUMER=>”+client.getMsg();
}}
NOTE: Here client.getMsg() method is nothing but HTTP Request call.
16
LoadBalancing in SpringCloud(MicroServices)
To handle Multiple Requests made by any HTTPClient (or consumer) in lesstime,
one Provider should run as multiple instances andhandle request in parallel such
concept is called as “LoadBalancing”.
LoadBalancing is to make request handling faster (reduce waiting time in queue).
17
Ribbon:
It is a Netflix component provided for SpringBootCloudLoadBalancing.
It is also called as “ClientSideLoadBalancing”. It means ConsumerApp,reads URI
(which one is free) using LBS Register.
Ribbon should be enabled by every consumer.
spring cloud uses LoadBalancerClient(I) for “choose and invoke” process.
Its implementation is provided by Ribbon.
=-=-CodingSteps=-=-=
#1In Provider, define InstanceId for PROVIDER APPLICATION using key
“eureka.instance.instance-id”. If not provided default is taken as SpringApp name.
eureka.instance.instance-id=${spring.application.name}:${random.value}
[add in application.properties]
#2In Consumer, add dependency for Ribbon and use LoadBalancerClient (Autowired)
and call choose(“APP-NAME”) method to get ServiceInstance (for URI)
Consumer Execution flow for Request:
18
FolderStructure:
EurekaServerCloudApplication.java
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaServerCloudApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaServerCloudApplication.class, args);
}
}
application.properties
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
19
OrderServiceProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassOrderServiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(OrderServiceProviderApplication.class, args);
}
}
OrderProvider.java:
package com.app.controller;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
publicclassOrderProvider {
@Value("${server.port}")
private String port;
@GetMapping("/status")
public String getOrderStatus() {
return"FINISHED::"+port;
}}
20
application.properties:
server.port=9803
spring.application.name=ORDER-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
eureka.instance.instance-id=${spring.application.name}:${random.value}
If no instance-id is provided then application name (service Id) behaves as instance
-Id
InvoiceServiceProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassInvoiceServiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(InvoiceServiceProviderApplication.class, args);
}
21
application.properties:
server.port=8800
spring.application.name=INVOICE-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
OrderConsumer.java:
package com.app.consumer;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
importorg.springframework.http.ResponseEntity;
importorg.springframework.stereotype.Service;
importorg.springframework.web.client.RestTemplate;
@Service
publicclassOrderConsumer {
@Autowired
privateLoadBalancerClientclient;
public String getStatus() {
String path="/order/status";
ServiceInstanceinstance=client.choose("ORDER-PROVIDER");
String uri=instance.getUri().toString();
RestTemplatert=newRestTemplate();
ResponseEntity<String>resp=rt.getForEntity(uri+path, String.class);
return"CONSUMER=>"+resp.getBody();
}
}
InvoiceProvider.java:
package com.app.controller;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.consumer.OrderConsumer;
@RestController
@RequestMapping("/invoice")
publicclassInvoiceProvider {
@Autowired
privateOrderConsumerconsumer;
@GetMapping("/info")
public String getOrderSatus() {
returnconsumer.getStatus();
}}
22
Execution:
a. start Eureka Server
b. Run OrderProvider starter class 3 times
*** Change every time port number like: 9800,9801, 9802
c. Run InvoiceProvider Starter class
d. Goto Eureka and Execute Invoice Provider Instance type full URL
http://localhost:8080/invoice/info
outputs:
23
Load Balancing using Feign Client
Incase of Manual Coding for load Balancing Ribbon Component is used with Type
“LoadBalancingClient” (I).
Here, using this programmer has to define logic of consumer method.
Feign Client reduces coding lines by Programmer, by generating logic/code at
runtime.
Feign Client uses abstraction Process, means Programmer has to provide path with
Http Method Type and also input, output details.
At Runtime RibbonLoadBalancerClient instance is used to choose serviceInstance
and make HTTP call.
Example:
Step #1: Create Spring Starter Project for Eureka Server with port 8761 and
dependency “EurekaServer”.
FolderStructure:
EurekaServerAppApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
24
publicclassEurekaServerAppApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaServerAppApplication.class, args);
}
}
application.properties:
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
CartProviderApplication.java:
package com.app;
25
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassCartProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(CartProviderApplication.class, args);
}
}
Cart.java:
packagecom.app.model;
publicclass Cart {
private Integer cartId;
private String cartCode;
private Double cartFinalCost;
public Cart() {
super();
}
public Cart(Integer cartId, String cartCode, Double cartFinalCost) {
super();
this.cartId = cartId;
this.cartCode = cartCode;
this.cartFinalCost = cartFinalCost;
}
public Integer getCartId() {
returncartId;
}
publicvoidsetCartId(Integer cartId) {
this.cartId = cartId;
}
public String getCartCode() {
returncartCode;
}
publicvoidsetCartCode(String cartCode) {
this.cartCode = cartCode;
}
public Double getCartFinalCost() {
returncartFinalCost;
}
publicvoidsetCartFinalCost(Double cartFinalCost) {
this.cartFinalCost = cartFinalCost;
}
26
@Override
public String toString() {
return"Cart [cartId=" + cartId + ", cartCode=" + cartCode + ",
cartFinalCost=" + cartFinalCost + "]";
}
}
CartServiceProvider.java:
packagecom.app.provider;
importjava.util.Arrays;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.model.Cart;
@RestController
@RequestMapping("/cart")
publicclassCartServiceProvider {
@Value("${server.port}")
private String port;
@GetMapping("/info")
public String getMsg() {
return"CONSUMER:"+port;
}
@GetMapping("/data")
public Cart getObj() {
returnnew Cart(109, "ABC:"+port, 636.36);
}
@GetMapping("/list")
public List<Cart>getBulk() {
returnArrays.asList(
new Cart(101, "A:"+port, 636.36),
new Cart(102, "B:"+port, 526.46),
new Cart(103, "C:"+port, 839.38)
);
}
}
application.properties:
server.port=8603
spring.application.name=CART-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
eureka.instance.instance-id=${spring.application.name}:${random.value}
27
output:
@FeignClient(name="CART-PROVIDER")
publicinterfaceCartServiceConsumer {
@GetMapping("/cart/info")
public String getMsg() ;
@GetMapping("/cart/data")
public Cart getObj() ;
@GetMapping("/cart/list")
public List<Cart>getBulk();
}
Cart.java:
packagecom.app.model;
publicclass Cart {
private Integer cartId;
private String cartCode;
private Double cartFinalCost;
public Cart() {
super();
}
public Cart(Integer cartId, String cartCode, Double cartFinalCost) {
super();
this.cartId = cartId;
this.cartCode = cartCode;
this.cartFinalCost = cartFinalCost;
}
public Integer getCartId() {
returncartId;
}
publicvoidsetCartId(Integer cartId) {
this.cartId = cartId;
}
public String getCartCode() {
returncartCode;
}
publicvoidsetCartCode(String cartCode) {
this.cartCode = cartCode;
}
29
public Double getCartFinalCost() {
returncartFinalCost;
}
publicvoidsetCartFinalCost(Double cartFinalCost) {
this.cartFinalCost = cartFinalCost;
}
@Override
public String toString() {
return"Cart [cartId=" + cartId + ", cartCode=" + cartCode + ",
cartFinalCost=" + cartFinalCost + "]";
}
}
PaymentServiceProvider.java:
packagecom.app.provider;
importjava.util.List;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.consumer.CartServiceConsumer;
importcom.app.model.Cart;
@RestController
@RequestMapping("/payment")
publicclassPaymentServiceProvider {
@Autowired
privateCartServiceConsumerconsumer;
@GetMapping("/message")
public String getMsg() {
returnconsumer.getMsg();
}
@GetMapping("/one")
public Cart getOneRow() {
returnconsumer.getObj();
}
@GetMapping("/all")
public List<Cart>getAllRows(){
returnconsumer.getBulk();
}
}
application.properties:
server.port=9890
spring.application.name=PAYMENT-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
30
output:
31
Spring Cloud Confgi Server
It is also called as Configuration Server. In Spring Boot/Cloud Projects, it contains
files like : properties files [application.properties]
In some cases Key=Values need to be changed (or) new key=value need to be
added. At this time, we should
-->Stop the Server (Application)
-->Open/find application.properties file
-->Add External key=value pairs or do modifications.
-->Save changes [save file]
-->Re-build file [re-create jar/war]
-->Re-Deploy [re-start server]
And this is done in All related Project [ multiple microservices ] which is repeated
task for multiple applications.
*#*To avoid this repeated (or lengthy) process use “application.properties” which is
placed outside of your Project. i.e. known as “ConfigServer”.
Config server process maintains three (3) properties file. Those are:
a. One in = Under Project (Microservice)
b. One in = Config Server (link file)
c. One in = Config server(native) (or)outside ConfigServer(External)also called
as Source file.
Spring cloud Config server can be handled in two ways. Those are
1. Native Config Server
2. External Config Server
1.Native Config Server:It is also called as local file placed in Config server only.
2.External Config Server: In this case properties file is placed outside the Config
server. Ex: GIT (github)
32
Config server runs at default port=8888.
2# (GIT ConfigServer)
ExternalConfigServer
case#b) External
application.properties
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/venkatadri053/config-server-ex
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
(or)
Create Git Project “configserverex” and create application.properties inside
this.place above key and save file.
---ExecutionOrder----
Eureka Server Config Server Producer(Provider) Consumer
EurekaserverApplication.java:
34
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaserverApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaserverApplication.class, args);
}
}
application.properties:
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
output:
35
ConfigServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
publicclassConfigServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
myapp.properties:
##Source Fie##
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
application.properties:
##link file##
server.port=8888
spring.profiles.active=native
spring.cloud.config.server.native.search-locations=classpath:/myapp-config
36
InvoiceProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
publicclassInvoiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(InvoiceProviderApplication.class, args);
}
}
OrderConsumer.java:
package com.app.consumer;
importorg.springframework.cloud.openfeign.FeignClient;
importorg.springframework.web.bind.annotation.GetMapping;
@FeignClient(name="ORDER-PROVIDER")
publicinterfaceOrderConsumer {
@GetMapping("/order/show")
public String showMsg();
}
InvoiceServiceProvider.java:
packagecom.app.provider;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.consumer.OrderConsumer;
@RestController
@RequestMapping("/invoce")
publicclassInvoiceServiceProvider {
@Autowired
privateOrderConsumerconsumer;
@GetMapping("/info")
public String getConsumerMsg() {
return"Consumer=>"+consumer.showMsg();
}
}
application.properties:
server.port=9500
spring.application.name=INVOICE-PROVIDER
Output:
37
Step#4 Create Consumer Project (Invoice)
Dependency : web,EurekaDiscovery,Configclient,Feign
Write application.properties
Add @EnableFeignClient annotation
Writer Consumer [Feign Client] and Invoice provider (RestController)
FolderStructure:
InvoiceProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
publicclassInvoiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(InvoiceProviderApplication.class, args);
}
}
38
OrderConsumer.java:
package com.app.consumer;
importorg.springframework.cloud.openfeign.FeignClient;
importorg.springframework.web.bind.annotation.GetMapping;
@FeignClient(name="ORDER-PROVIDER")
publicinterfaceOrderConsumer {
@GetMapping("/order/show")
public String showMsg();
}
InvoiceServiceProvider.java:
packagecom.app.provider;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.consumer.OrderConsumer;
@RestController
@RequestMapping("/invoce")
publicclassInvoiceServiceProvider {
@Autowired
privateOrderConsumerconsumer;
@GetMapping("/info")
public String getConsumerMsg() {
return"Consumer=>"+consumer.showMsg();
}
}
application.properties:
server.port=9500
spring.application.name=INVOICE-PROVIDER
Output:
39
Steps to configure External ConfigServer:(only modifications)
Step#1 in config server project,delete folder myapp-config
Step#4 Create git account and create config-server-ex repository. Under this create
file application.properties
EurekaServer:
FolderStructure:
40
EurekaserverApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaserverApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaserverApplication.class, args);
}
}
application.properties:
server.port=8761
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
ConfigServer:
FolderStructure:
41
ConfigServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer
publicclassConfigServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
application.properties:
##link file##
server.port=8888
spring.cloud.config.server.git.uri=https://github.com/venkatadri053/config-server-ex
OrderProvider:
FolderStructure:
OrderProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassOrderProviderApplication {
publicstaticvoid main(String[] args) {
42
SpringApplication.run(OrderProviderApplication.class, args);
}
}
OrderServiceProvider.java:
packagecom.app.provider;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/order")
publicclassOrderServiceProvider {
@GetMapping("/show")
public String showMsg() {
return"From Provider";
}
}
application.properties:
server.port=9800
spring.application.name=ORDER-PROVIDER
eureka.instance.instance-id=${spring.application.name}:${random.value}
Output:
43
InvoiceProvider:
FolderStructure:
InvoiceProviderApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
importorg.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
publicclassInvoiceProviderApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(InvoiceProviderApplication.class, args);
}
}
OrderConsumer.java:
package com.app.consumer;
importorg.springframework.cloud.openfeign.FeignClient;
importorg.springframework.web.bind.annotation.GetMapping;
@FeignClient(name="ORDER-PROVIDER")
publicinterfaceOrderConsumer {
@GetMapping("/order/show")
public String showMsg();
}
InvoiceServiceProvider.java:
packagecom.app.provider;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.GetMapping;
44
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.app.consumer.OrderConsumer;
@RestController
@RequestMapping("/invoce")
publicclassInvoiceServiceProvider {
@Autowired
privateOrderConsumerconsumer;
@GetMapping("/info")
public String getConsumerMsg() {
return"Consumer=>"+consumer.showMsg();
}
}
application.properties:
server.port=9500
spring.application.name=INVOICE-PROVIDER
Output:
45
Config Server With Provider/Consumer Execution flow[External Source]
On startup ConfigServer(CS) Application it will goto External Source (Git) and read
____.properties (or) ____.yml file having key=value pairs.
Then Provider/Consumer Application (on startup) will try to read k=v from config
server and merge with our application properties.
If same key is found in both Config Server and Provider/Consumer App,then 1st
priority is : ConfigServer.
After fetching all required properties then Provider gets Registered with
EurekaServer.
Execution Order:
Parent Project-loads-bootstrap.properties /bootstrap.yml
Our Project-loads-application.properties /application.yml
We can override this file in our project to provide key-values to be loaded by
Parent Project.
**) by default, Config Server runs on http://localhost:8888 even config client also
takes this as default location.
**) To modify this IP/PORT use bootstrap.properties file in Our Project.
**) In this bootstrap.properties file override key: spring.cloud.config.urito any other
location where Config server is running.
46
DIAGRAM:
Q)which class will load bootstrap.properties file for Config Server URI fetching?
A)ConfigServicePropertySourceLocator will read config server input by default from
http://localhost:8888.
It is only first execution step in Provider/Consumer Project.
47
Fault Tolerance API
If any Microservice is continuously throwing Exceptions, then logic must not be
executed every time also must be finished with smooth termination. such Process is
called as “Fault Tolerance”.
Fault Tolerance is achieved using FallBackMethod and CircuitBreaker.
Hystrix:It is a API (set of classes and interfaces) given by Netflix to handle Proper
Execution and Avoid repeated exception logic (Fault Tolerance API) in Microservice
Programming.
It is mainly used in production Environment not in Dev Environment.
Hystrix supports FallBack and CircuitBreaker process.
It provides Dashboard for UI. (View problems and other details in Services).
48
@EnableCIrcuitBreaker will find concept at runtime using pom.xml dependency
ex: Hystrix, Turbine etc…
whereas @EnableHystrix will execute only HystrixCIrcuitBreaker.
Step#1:-- Create Spring Starter Project with Dependencies : web, eureka discovery,
Hystrix.
Hystrix Dependency:--
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
GroupId : org.sathyatech
ArtifactId : Spring_Cloud_Hystrix_Server
Version : 1.0
=>Finish
49
importorg.springframework.cloud.netflix.hystrix.EnableHystrix;
@SpringBootApplication
@EnableDiscoveryClient
@EnableHystrix
publicclassHystrixServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(HystrixServerApp.class, args);
}
}
Step#3:--application.properties file:--
server.port=9800
spring.application.name=ORDER-PROVIDER
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka
packagecom.app.provider;
importjava.util.Random;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RestController;
importcom.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
@RestController
publicclassOrderServiceProvider {
@GetMapping("/show")
@HystrixCommand(fallbackMethod="showFallBack")
//parameter must be same as fallBackMethod name
public String showMsg() {
System.out.println("From service");
if (new Random().nextInt(10)<=10)
{
thrownewRuntimeException("DUMMY");
}
return"Hello From Provider";
}
//fallBack method
public String showFallBack() {
System.out.println("From ballback");
return"From FallBack method";
}
50
}
Execution Process:--
Step#5:-- Run Eureka Server and Order Provider.
Step#6:--Goto Eureka and Execute ORDER PROVIDER and enter URL path :/show
(http://192.168.100.39:9800/show)
51
SpringCloud Netflix MicroService Design
Accessing these by client will be complicated.so, all are accessed through one
entrypoint which makes
*Spring Cloud Netflix ZUUL behaves as API PROXY for Microservices Application
which supports “Integration with any type of client component”(web,mobile,3 rd
party webservices..etc)
52
ZUUL (APIPROXY) Working flow:
server.port=8558
eureka.client.service-url.default-zone=http://localhost:8761/eureka
spring.application.name=ZUUL-PROXY
zuul.routes.<module>.path=/<module>-api/**
zuul.routes.<module>.service-id=[SERVICE-ID]
53
Step#3 In ZuulServer project, at starter class level add annotation:@EnableZuulProxy
ZUUL ExampleService:
zuul.routes.item.path=/item-api/**
zuul.routes.item.service-id=ITEM-SERVICE
zuul.routes.cart.path=/cart -api/**
zuul.routes.cart.service-id=CART-SERVICE
If two modules are provided in Zuul then, only module name gets changed in keys.
Consider below example:
MODULE PATH SERVICE-ID
Product /prod-api/** PROD-SERVICE
Student /std-api/** STD-SERVICE
application.properties:
zuul.routes.product.path=/prod-api/**
zuul.routes.product.service-id=PROD-SERVICE
zuul.routes.student.path=/std-api/**
zuul.routes.student.service-id=STD-SERVICE
54
EUREKA SERVER:
FolderStructure:
EurekaServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaServerApplication {
application.yml:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
55
Output:
ZUULSERVER:
FolderStructure:
ZuulServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
importorg.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
publicclassZuulServerApplication {
publicstaticvoid main(String[] args) {
56
SpringApplication.run(ZuulServerApplication.class, args);
}
}
application.yml:
server:
port: 9999
spring:
application:
name: ZUUL-PROXY
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
zuul:
routes:
item:
path: /item-api/**
service-id: ITEM-SERVICE
Output:
57
ITEMPROJECT:
FolderStructure:
ItemProjectApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassItemProjectApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ItemProjectApplication.class, args);
}
}
ItemProvider.java:
packagecom.app.provider;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/item")
publicclassItemProvider {
@Value("${server.port}")
private String port;
@GetMapping("/find")
58
public String findItem() {
return"ITEM FOUND:"+port;
}
}
application.yml:
server:
port: 9966
spring:
application:
name: ITEM-SERVICE
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${random.value}
output:
59
Working with ZUUL Filter:
Filters are used to validate request construct valid response. In simple , we also call it
as “PRE-POST” processing logic.
ZUUL Filter provides even extra types like ROUTE FILTERS and ERROR FILTERS.
When client made request to ZUUL then Pre Filter gets called automatically.
After validating, request is dispatched to Route Filter.
Route Filter is like 2nd level validation at required SERVICE level.
Route Filter will dispatch request to one Microservice based on Service-Id
If microservice is not executed properly(i.e. throwing exception) then Error
filter is called.
Finally Post Filter works on Http Response (adds Headers, Encode data, Provide
info to client..etc.) in case of either success or failure.
Here, filter is a class must extends one abstract class “ZuulFilter” provided by
Netflix API.
We can define multiple filters in one application. Writing Filters are optional.
While creating filter class we must provide Filter Order (0, 1, 2,3…) and Filter
type (“pre”, “route”, “error”, “post”)
Two filters of same type can have same order which indicates any execution
order is valid.
We can enable and disable filters using its flags (True/False).
60
To indicate Filter types, we use its equal constants (public static final string
variables), provides as
Type Constant
pre PRE_TYPE
route ROUTE_TYPE
error ERROR_TYPE
post POST_TYPE
All above constants are defined in FilterConstants (C) as global variables (public
static final string)
Write one class in ZUUL server and extend ZuulFilter Abstract class, override
below 4 methods in your filter.
shouldFilter() – Must be set to ‘true’. If value is set to false then filter will not
be executed.
run() – contains Filter logic. Executed once when filter is called.
filterType() – Provides Filter Constant. Must be one Type(pre, post, route, error)
filterOrder() – Provides order for Filter. Any int type number like: 0, 56, 98.
EurekaServer:
FolderStructure:
61
EurekaServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
publicclassEurekaServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml:
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
output:
ZUUL SERVER:
FolderStructure:
62
ZuulServerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
importorg.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
publicclassZuulServerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ZuulServerApplication.class, args);
}
}
ErrorTypeFilter.java:
packagecom.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
importorg.springframework.stereotype.Component;
importcom.netflix.zuul.ZuulFilter;
importcom.netflix.zuul.exception.ZuulException;
@Component
publicclassErrorTypeFilterextendsZuulFilter{
/**Enable(true) or Disable Filter(false)**/
publicbooleanshouldFilter() {
returntrue;
63
}
/**Define Filter Logic Here**/
public Object run() throwsZuulException {
System.out.println("FROM ERROR FILTER");
returnnull;
}
/**Specify Filter Type**/
public String filterType() {
returnFilterConstants.ERROR_TYPE;
}
/**Provider Filter Order for Execution**/
publicintfilterOrder() {
return 0;
}
}
PostTypeFilter.java:
packagecom.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
importorg.springframework.stereotype.Component;
importcom.netflix.zuul.ZuulFilter;
importcom.netflix.zuul.exception.ZuulException;
@Component
publicclassPostTypeFilterextendsZuulFilter{
/**Enable(true) or Disable Filter(false)**/
publicbooleanshouldFilter() {
returntrue;
}
/**Define Filter Logic Here**/
public Object run() throwsZuulException {
System.out.println("FROM POST FILTER");
returnnull;
}
/**Specify Filter Type**/
public String filterType() {
returnFilterConstants.POST_TYPE;
}
/**Provider Filter Order for Execution**/
publicintfilterOrder() {
return 0;
}
}
64
PreTypeFilter.java:
packagecom.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
importorg.springframework.stereotype.Component;
importcom.netflix.zuul.ZuulFilter;
importcom.netflix.zuul.exception.ZuulException;
@Component
publicclassPreTypeFilterextendsZuulFilter{
/**Enable(true) or Disable Filter(false)**/
publicbooleanshouldFilter() {
returntrue;
}
/**Define Filter Logic Here**/
public Object run() throwsZuulException {
System.out.println("FROM PRE FILTER");
returnnull;
}
/**Specify Filter Type**/
public String filterType() {
returnFilterConstants.PRE_TYPE;
}
/**Provider Filter Order for Execution**/
publicintfilterOrder() {
return 0;
}
}
RouteTypeFilter.java:
packagecom.app.filter;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
importorg.springframework.stereotype.Component;
importcom.netflix.zuul.ZuulFilter;
importcom.netflix.zuul.exception.ZuulException;
@Component
publicclassRouteTypeFilterextendsZuulFilter{
/**Enable(true) or Disable Filter(false)**/
publicbooleanshouldFilter() {
returntrue;
}
/**Define Filter Logic Here**/
public Object run() throwsZuulException {
System.out.println("FROM ROUTE FILTER");
returnnull;
65
}
/**Specify Filter Type**/
public String filterType() {
returnFilterConstants.ROUTE_TYPE;
}
/**Provider Filter Order for Execution**/
publicintfilterOrder() {
return 0;
}
}
application.yml:
server:
port: 9999
spring:
application:
name: ZUUL-PROXY
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
zuul:
routes:
item:
path: /item-api/**
service-id: ITEM-SERVICE
Output:
66
ItemProject:
FolderStructure:
ItemProjectApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
publicclassItemProjectApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ItemProjectApplication.class, args);
}
}
ItemProvider.java:
packagecom.app.provider;
importorg.springframework.beans.factory.annotation.Value;
importorg.springframework.web.bind.annotation.GetMapping;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/item")
publicclassItemProvider {
@Value("${server.port}")
private String port;
@GetMapping("/find")
67
public String findItem() {
return"ITEM FOUND:"+port;
}
}
application.yml:
server:
port: 9900
spring:
application:
name: ITEM-SERVICE
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${random.value}
output:
BrowserOutput:
68
ConsoleOutput:
PROJECT LOMBOK
This is open source JAVA API is used to avoid writing (or generating) common code
for Bean/Model/Entity classes.
That is like:
1. Setters and Getters
2. toString() method
3. Default and Parameterized constructor
4. hashCode() and equals() methods.
Programmer can write these methods manually or generate using IDE. But if
any modification(s) are done in those classes then again generate set/get
methods also delete and write code for new : toString, hashCode, equals and
Param const ( it is like repeated task)
By using Lombok API which reduces writing code or generating task for Beans.
Just apply annotations, it is done.
To use lombok, while creating Spring Boot Project choose dependency:
Lombok (or) Add below dependency in pom.xml
(For spring boot project: do not provide version. it is provided by spring boot
parent only.)
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
69
Installation of Lombok in IDE:
1) Open STS/Eclipse (any workspace)
2) Create spring boot project with Lombok Dependency (or) maven project with
above Lombok Dependency.
3) Update Maven Project
4) Close STS.
5) Go to lombok jar location
For e.g.:
C:\Users\<username>\.m2\repository\org\projectlombok\lombok\1.18.6
6) open command Prompt here
Shift + Mouse Right click
Choose “Open Command Window Here”
Type cmd given below
Java -jar lombok-1.18.6.jar
Wait for few minutes (IDEs are detected)
Click on Install/Update
Finish
7) Open STS/Eclipse and start coding
=-=-=-=-Example application=-=-=-=-=
#1 create spring Boot starter project
File >new spring starter project enter details:
GroupId : com.app
ArtifactId : SpringBootLombok
Version: 1.0
Choose dependency : lombok (only)
70
Note:
*#*:Apply @Data (package : lombok.Data) over Bean/Model which generates Set,
get, toString, equals, hashCode and RequiredArgs Constructor.
E.g.:
@Data
public class Employee {………….}
FolderStructure:
LombokExampleApplication.java:
packagecom.demo.venky;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclassLombokExampleApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(LombokExampleApplication.class, args);
}
}
Employee.java:
packagecom.demo.venky.model;
71
importlombok.Getter;
importlombok.NoArgsConstructor;
importlombok.NonNull;
importlombok.RequiredArgsConstructor;
importlombok.Setter;
importlombok.ToString;
//@Data //Generates all (get,set,constructorstostring )methods
@Getter //Generates get methods
@Setter //Generates set methods
@ToString //override toString method
@NoArgsConstructor //generate default constructor
@RequiredArgsConstructor//override hashcode , equals method
publicclass Employee {
@NonNull
private Integer empId;
@NonNull
private String empName;
private Double empSal;
}
MyAppRunner.java:
packagecom.demo.venky.runner;
importorg.springframework.boot.CommandLineRunner;
importorg.springframework.stereotype.Component;
importcom.demo.venky.model.Employee;
@Component
publicclassMyAppRunnerimplementsCommandLineRunner {
publicvoid run(String... args) throws Exception {
Employee e1=new Employee();
e1.setEmpId(10);
e1.setEmpName("AA");
e1.setEmpSal(6.66);
Employee e2=new Employee();
e2.setEmpId(20);
e2.setEmpName("BB");
e2.setEmpSal(7.77);
Employee e3=new Employee();
e3.setEmpId(30);
e3.setEmpName("CC");
e3.setEmpSal(9.99);
}
}
72
Output:
In case of real time application large data needs to be transferred and processed.
Like google server to amazon, facebook, … etc.
Data (Message) transfer can be done using Message Queues.
Message Queues are used for
a. Log aggregation (Read Large Log files from server and sent to another place)
b. Web Activities (Know what users are searching and provide related links
and Advertisement in client websites)
c. Command Instruction (send message to Printer/Email one invoice on
receive)
d. Data Streaming (Read large data from files, Networks, Databases
continuously)etc..
In case of multiple clients sharing data without MQ, may look like this:
73
MQ can be implemented using Language based technologies (or API)
Ex: JMS (Java Message Service)
Global MQ (between any type of client) Advanced Message Queuing protocol
(AMQP)
Apache ActiveMQ, Rabbit MQ, Apache Atrims are different Service providers
(Broker software’s) for JMS
Apache Kafka is a service Provider (Broker software) for AMQP.
74
Limitations of JMS:
a. Used between Java Applications.
b. Message(Data) size should be smaller
c. Only one MOM (one instance) runs at a time.
d. Large data takes lot of time to process.
e. If Pub/Sub model is implemented with more consumers then process will be
very slow
f. Day may not be delivered (data lose) in case of MOM stops Restart.
75
Steps to Implements ActiveMQ:
Step#1 Create one Spring boot starter application using dependencies:
(or add below dependency in pom.xml)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activeMQ</artifactId>
</dependency>
Step#3 If applicationis Producer type then use JmsTemplate object and call send()
which will send message to MOM.
Step#4 If Application is Consumer type then define one Listener class using
destination.
76
Producer FolderStructure:
SpringBootActiveMqProducerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
publicclassSpringBootActiveMqProducerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(SpringBootActiveMqProducerApplication.class, args);
}
}
MessageProducer.java:
package com.app.producer;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.CommandLineRunner;
importorg.springframework.jms.core.JmsTemplate;
importorg.springframework.stereotype.Component;
@Component
publicclassMessageProducerimplementsCommandLineRunner{
@Autowired
privateJmsTemplatetemplate;
@Override
publicvoid run(String... args) throws Exception {
template.send("my-tpca", (ses)->ses.createTextMessage("AAAAAAAAA"));
System.out.println("sent from Producer");
}
}
77
application.yml:
spring:
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
jms:
pub-sub-domain: true
ConsoleOutput:
Consumer FolderStructure:
SpringBootActiveMqConsumerApplication.java:
package com.app;
importorg.springframework.boot.SpringApplication;
importorg.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
publicclassSpringBootActiveMqConsumerApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(SpringBootActiveMqConsumerApplication.class, args);
}
}
78
MyMessageConsumer.java:
package com.app.consumer;
importorg.springframework.jms.annotation.EnableJms;
importorg.springframework.jms.annotation.JmsListener;
importorg.springframework.stereotype.Component;
@EnableJms
@Component
publicclassMyMessageConsumer {
@JmsListener(destination = "my-tpca")
publicvoidreadMessage(String msg) {
System.out.println("from consumer");
System.out.println("msg is:"+msg);
}
}
application.yml:
spring:
activemq:
broker-url: tcp://localhost:61616
user: admin
password: admin
jms:
pub-sub-domain: true
BrowserOutput:
79
Spring Boot Apache Kafka Integration
Apache Kafka is used for
A. Distributed Messaging System, which works for multiple destinations of any
type (any Language +Plugin required), to send or receive Messages.
B. Supports Realtime Data Streaming. It means read continuous and Large data
from external source like Float Files, Database, networks, etc.…
C. Message Brokers will persist the message (save into their memory) to avoid
data lose in case of consumer non-available or broker is down.
D. Kafka Default communication type is Pub/Sub (Topics).
E. Kafka Supports Load Balancing for Broker Softwire’s to make execution faster. It
is known as Kafka Cluster.
F. All these Broker instances must be Registered with Registry and Discovery (R&D)
Server. Kafka comes with default “Zookeeper R&D Server”.
G. This complete Kafka Software is called as Kafka Ecosystem (= Kafka Cluster +
R&D Server)
H. Kafka works as Protocol independent i.e. works for TCP, FTP, SMTP, HTTP… etc.)
Execution Flow:
Producer Application should get Message Broker details from R & D Server
(zookeeper) known as bootstrap-server).
Producer gets unique-id of Message Broker server and sends message to Broker.
MessageBroker will send this message to one or multiple consumers.
80
Producer sends data <k, V> format in Serialized (Converting to binary/Characters
formats). Here K=Destination (Topic name) and V= Message.
Every Message will be partitioned into Multiple parts in Topic (Destination) to
avoid large data sending, by making into small and equal parts (some time size may
vary).
Broker reads all partitions data and creates its replica (Clone/Mirror obj) to send
message to multiple consumers based on Topic and Group-Id.
At Consumer side Deserialization must be applied on K, V to read data. Consumer
should also be linked with bootstrap-server to know its broker.
Partitions are used to breakdown large message into multiple parts and send same
to multiple brokers to make data destination in parallel.
Message Replica: it creates multiple copies to one message to publish one
message to multiple Consumers.
2Server.bat
Starts Kafka Server (Message Broker)
.\bin\windows\kafka-server-start.bat .\config\server.properties
Coding Steps:
Step#1 Create new Spring boot Starter project with dependencies: web, kafka
GroupId: com.app
ArtifactId: SpringBootKafkaApp
version: 1.0
Kafka Dependency:
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
FolderStructure:
82
Step#2 add key= value pairs in application (. properties/. yml) file.
server:
port: 9988
spring:
kafka:
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
consumer:
bootstrap-servers: localhost:9092
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
group-id: groupId
my:
app:
topicname: sampletopic
output:
85
Spring Boot with Apache Camel
Routing:It is a process of sending large data from Application (Source) to another
Application (Destination). Here data can be File System(.xml, .txt, .csv, .xlsx, .json,
etc..), Database (Oracle DB, MySQL Db) or Message Queues using JMS (Active MQ)
etc..
Apache Camel is OpenSource and Light weight “Conditional based Routing Engine”
which supports filtering and processing.
Apache Camel also supports different language like PHP, Python, and JavaScript…
etc.
Compared to Spring Batch Integration tool Apache camel is a light weight tool.
Camel supports reading data from different sources even like HTTP, FTP, JMS
protocols based.
Daigram:
Step#2: Camel avoid main method (thread) execution control and run as
independent while working with Spring boot, our starter class is main method. So,
we should add key=value in properties file as
application.properties:
camel.springboot.main-run-controller=true
86
Step#3: Define one Route Builder class and configure details of routing, filtering and
processing.
To implement this, we need to write one class using (Abstract class)
RoutingBuilder provided by Apache camel having one abstract method: configure()
which contains coding format like:
from (SourceLocation)
. [filter] . [process].
.to (DestinationLocation)
Here Location can be URL/Local File System DB, JMS (MessageQueues)… etc.
Coding Steps:
Step#1: Create Spring Boot starter application with dependencies: Apache Camel
GroupId: org.sathyatech
ArtifactId: SpringBootApacheCamel
Version: 1.0
Step#2: open application.properties (.yml) and add main method-control key as true.
application.properties:
camel.springboot.main-run-controller=true
(OR)
application.yml:
camel:
springboot:
main-run-controller=true
Step#5: Start Application and place files in “D:/source” which will be copied to
“D:/destination”.
EIP Patterns by Apache Camel: EIP stand for “Enterprise Integration Patterns” used
to define short form code for
Data routing
Data Filtering
Data Processing
#3 from (“{{source}}”).to(“{{destination}}”)
Here {{location}} indicates dynamic location passing using Properties/Yml files,
System args, command line inputs etc.
Example EIPs:
#1Dynamic Location:
Location (source/destination) can be passed at runtime using properties/yml files,
config server, system arguments… etc.
To indicate Location (URL file System, DB, MQ…) comes at runtime use format:
{{location}}
Code changes
a. applictaion.properties:
camel.springboot.main-run-controller=true
my.source=file:D/source?noop=true
my.destination=file:/desti
***Note:Here file name indicates new name for modified message. It can also be
passed at run time.
89
Using Lambda Expression## code:
from(“file:D:/source”)
.process(ex{
String body=ex.getIn().getBody(String.class);
Body=”New AA modified ::”+body;
ex.getOut().setBody(body);
})
.to(“file:D:/destination?fileName=myFile.txt”);
Example:
from(“file:D:/source”)
. choice()
.when(body().startWith(“java”))
.to(“file:D:/destinatation?fileName=a.txt”)
. when(body(). startWith(“xml”)).to(“file:D:/destinatation?fileName=b.txt”)
. when(body(). startWith(“xml”)).to(“file:D:/destinatation?fileName=b.txt”)
. otherwise().to(“file:D://destinatation?fileName=d.txt”);
91
Step#2 add below dependencies in pom.xml file
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-jms</artifactId>
<version>2.23.2</version>
</dependency>
Output:
93
Open Authorization (OAuth 2.x)
OAuth 2.x is standard and framework which provides 3 rd party security services to
client application which are registered, on behalf of end user.
These 3rd party Applications are also called as “Authorization and Resource
Servers”.
OAuth 2.x standard is widely used in small/medium scale/daily used, business
application.
OAuth2 Provide SSO (Single Sign on) for multiple applications acting as a one
Service.
Example Client Application are: bookmyshow, yetra.com, quora, redbus,
makemytrip, Netflix, mediafire, avast.com, carwale.com, zomato.com.
***OAuth2 may not be used for high level and Large scale applications (Ex:-
Banking Creditcard, Stock Market… etc). These Spring Security ORM is used mostly.
Few Authorization and Resource Servers are : Google, facebook, Redit, Github,
Twitter, Linkedin… etc.
Work flow of OAuth2:
Diagram:
94
OneTime setup for OAuth2:
Step #1 Choose any one (or more) 3rd party “Authorization and Resource Server”.
Ex:-- facebook, Google cloud platform (GCP) Github, Linkedin, Twitter… etc.
Step #2 Here choosing Facebook as 3rd party server for open Authorization link is:
https://developers.facebook.com/
Step #3 Define one new (client) Application in FB Authorization server which
generates ClientId (AppId) and secrete (App Secret)
Gotofacebook developer page
Click on top right corner ”MyApps”
95
Click on “Create AppId”.
Complete Security verification
Click on “Dashboard”
Click on “facebook Login” setup button
Click on “Settings” >>”Basic
96
Step #4 Create one SpringBoot Starter app with dependencies “Security” and “Cloud
OAuth2”.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
Step #5 Create application.yml file using below key value pairs.
application.yml:
server:
9898
security:
oauth2:
//Auth Server details
client:
clientId: <your clientId here>
clientSecret: <Your secret here>
accessTokenUri:
userAuthorizationUri:
tokenName:
authenticationSchema:
clientAuthenticationScheme:
#Resource Server details
resource:
userInfoUri:
97
Request Execution flow :
Package com.app.config;
@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter{
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRquests().antMatchers(“/”,”/login”).permitAll()
.anyRequest().authenticated();
}
}
Step#7 Define RestController for User (or Any
package com.app.controller;
@RestController
pubic classsUserRestController {
@RequestMapping(“/user”)
public Principal showUser(Principal p) {
return p;
}
98
@RequestMapping(“/home”)
public String showData() {
return “Hello”;
}
}
Step#8 Define one UI Page ex: index.html under src/main/resource, in static folder
Index.html:
<html><body>
<h1>Welcome to Login Page/</h1>
<a href=”user”>Facebook</a>
(or)
<hr/>
<form action=”#” method=”post”>
User : <input type=”text”>
Pwd : <input type=”password”>
<input type=”submit”>
</form>
</body></body></html>
99
Step#2: Enter details name, email, password and conform password Register
100
Step#4: Login to PCF account (Above URL)
101
Mobile number and verify
102
Organization (org) name > finish
103
next
nextnext Finish
Step#7: Login and Logout Commands
Gotocmd prompt
1.Login command is
cf login –a api.run.pivotal.io
Email >
Password >
2.Logout command is
cf logout
104
TASK:
Spring Boot WEB MVC + Thymeleaf + Data JPA + H2 (Curd Operation) + Bootstrap
Step#10: Write Code for RestController, Services, Dao, and properties/yml files etc.
Step#17:Once success then goto PCF WebConsole (browser) and click on space
“development”
To see total apps and running app.
=>Click on Route (URL) to execute app
=>Enter Paths to URL ex: /home/show …
TASK:
=>Create Project with MySQL DB with CURD operations and upload to PCF
=>Goto Market place and chose mysql provider enter details
Instance name : myappsql
Choose or/space:
>choose plan > finish
=>Come to Home >Click on org > space > service
=>click on MySQl services > Bind App
=>select Our Project > bind > re-start app
=>Enter URL in browser and execute.
107