Microservices with Spring Boot and Spring Cloud
14 min readApr 1, 2022
Web Service
- Definition: Software designed to support interoperable machine-to-machine interaction over a network
- service definition should define:
* request responses format
* request structure
* response structure
* endpoint - transport define how a service is called
* over HTTP or MQ (queue)
transport define how a service is called
- over HTTP or MQ (queue)
SOAP (simple object access protocol)
- restriction on format of xml that is exchange between service provider and service consumer
- soap define a specific xml request and response structure
- must have an envelope, header and body structure
- no restuction on transport, can use http or MQ
Restful (Representation State Transfer)
- A term coined by Roy Fielding, the person who developed http protocol
- architecture style
- Make the best use of http, use http to define the header and body, use http status code
- think in term of resources, define resources using concept already exist in http
- no restriction on data exchange format
- Must use HTTP for transport
JPA (Java Persistent API)
- Map Java object to SQL entry
- Without JPA, JDBC requires you to write query and write preparedStatement, which is difficult to maintain when table change
- JPA uses annotations like @Inheritance, @ManytoMany to map object to table
- JPA define the annotations and specify relationship. Hibernate provides the implementation.
Entity
- require a default no paramter constructor
Service
- a class to manage entity (save entity etc)
- Whenever we want to interacte with the database we need to be inside a transaction
- entityManager persist object
CommandLineRunner
- auto run by Spring as app start
- has a run method that we can do the insert action
Repository
- service is too repetitive if you have many entity ( similiar insert logic)
- repository is an interface that JPA will provide the implementation
- provide save() findbyId() method etc
- replace service
Restful web service
- start a spring project at start.spring.io
- Some useful dependencies
- Spring Web
- Spring Boot DevTools
- Spring Data JPA
- H2 Database (in memory database)
Controller
- controller handle http request (map method)
- use annotation like @RequestMapping(method = RequestMethod.GET, path = “/helloWorld”
- there is a short version: @GetMapping(path = x)
- To return an object(bean) in api response, the class must have getter for its property
- dispatcher servlet find the right controller to execute a request
- ResponseEntity response a status code (Step10)
- throw a exception with annotation to reurn error status like 404
- create a class extends from
ResponseEntityExceptionHandler
to make all controller return standard error response (Step12)
Validation
- check input is correct when calling api
- add annotation like @Size @Past
- In order to give api consumer useful message with validation fail, override the method handleMethodArgumentNotValid from ResponseEntityExceptionHandler (step15)
HATEOAS (Hypermedia as the Engine of Application State)
- make the api return data as well as return different actions we can perform on the data
- client make a request, and the next steps are handed to them in the response
- provides additional links to the request along with the response
- hard to maintain a list of links if we manually hard code them
- return EntityModel of <data> (step 15 5:25)
Internationalization (i18)
- customize language base on country
- during request, api cosumer can specify the language in header
- Accept-Language: fr
- add a new paramter call “locale” in controller method
- to avoid passing in locale in all parameter, we can read locale directly in LocaleContextHolder
- pick value in property files instead of hard coding response
- use messageSource to return value from property file
Content Negotiation
- specify return xml or json response
- api consumer speciy in header
- Accept: Application/xml
- automatically handle by spring boot when adding dependency com.fasterxml.jackson.dataformat
Swagger
- documentation that is automatically generated from code, to avoid maintance
- add dependency springdoc-openapi-ui
- type localhost:8080/swagger-ui.html
Actuator
- use for monitoring purpose, expose a bunch of url
- implement services that return response to these url
HAL Explorer
- provide a UI to navigate through the HATEOS and actuator links
Filtering
- When return a object from Get Request, we can filter some fields using @JsonIgnore on the field or on the class
- For dynamic filtering(filter different combinations of fields in different request), we can define MappingJacksonValue mapping
- step 25 (4:01)
Versioning
- Create two versions of the same service — step 27 (1:30)
- a basic way is to having different url for the request, call uri versioning
- another way is let client pass in a parameter, call request parameter versioning
- can use header parameter as well, call header versioning
- use the produces paramter (5:04). call accept header versioning / mime type versioning
- header versioning are harder to document because they are not automatically generted by swagger
Authentication
- Spring boot provided a basic security dependency
- When using it, change authenticaion to basic authentication and pass in the password copied from log
- change to custom password in local.properties
Richardson Maturity Model
- how restful is your service
- level 0: Expose SOAP web services in rest style
- level 1: Expose resources with proper URI
- level 2: level 1 + http protocal
- level 3: level 2 + HATEOAS
Web Service Best Practice
- Consumer first (documente help)
- make best use of http
- use http response code status
- No secure Info in URL
- Use Plurals
- Use nouns for resources (For exceptions, define a consistent approach)
Microservices
- Style to developmening a single application as a suite of small services
- These services are independently deployable
- REST
- Small well chosen deployable unit
- cloud enabled (have multiple deployed instance of the same service)
Advantage
- Adapte new technology and process easily
- Each microservices can be built with different technoloy
- Dynamic Scaling
- Faster release cycles
- because we are developing smaller component
Challenge
- Bounded Context
- How to identity the boundary for each micro services?
- it is an evolutionary process base on the knowledge we have at that time
- Configuration managment
- multiple instance & enviornment
- Dynamic scale up and down
- Visibility
- How to locate bug when you have so many micro services
- Pack of cards
- If one microservice go down, all the other micro services that depend on it also go down
Spring Cloud
- Spring cloud provides solution to the challenges above
- Configuration managment
- Spring Cloud Config Server
- Store all configuration in a git repo and SpringCloudConfigServer will expose the config to the services
- Dynamic scale up and down
- Ribbon Load Balancing
- distrubte load among all services
- Naming Server has 2 important feature
- all microservices register with the naming server
- provide url of the available instance of services for service
- Visibility and monitoring
- Ziplin Distributed Tracing
- trace a request across multiple components
- Netflix API Gateway
- Don’t have to implement basic features like logging in every microservice
- Fault tolerance (Pack of cards)
- Hystrix
- Configure a default response when a service is down
Microservices with spring cloud
- Give your microservice a good name in local.properties
- spring.application.name=””
- server.port=8888
Pick up value from application.properties
- Create a configuration class with @ConfigurationProperties
Spring Cloud Config Server
- it is its own microservice
- Have a folder with a bunch of local.properties files and trcked by git
- Have this config server microservice point to this folder with:
- spring.cloud.config.server.git.uri = file:///{}path (yes 3 / ) (step6)
- on localhost:8888/limits-service/default we can see the local.properties files value
- On the micro service who want to use this config server (step7)
- Define config client dependency in spring.io
- or import spring-cloud-starter-config in xml
- on local.properties
- spring.config.import=optional:configserver:http://localhost:8888
- To support dev / qa / prod env configs, name the git file limits-service-dev.properties (step8)
- on localhost:8888/limits-service/dev we can see the local.properties files value
- on limit microservice set local.propertiesspring.profiles.active=dev
- and spring.cloud.config.profile=dev
Setting up Dynamic Port in the Response
- We can run multiple instances of the same microservices by specifying the port number in IDE’s Run Configurations
- (Step 12 4:16) Go to VM arguments -Dserver.port=8001., will override what is in application.properties
- There is a class call Enviornment that we can get the port and pass back in response if needed
Feign
- To call one microservice from another microservice
- Without Feign: return a RestTemplate with the other service’s url (step 17 4:59)
- (step 18) Create a Proxy interface and just call the method of that proxy in controller
Eureka Naming Server (Service Registery)
- For different instances of the microservices, we don’t want to hard code the url:port because they might went down
- This naming server itself is another microservices (Step 19)
- Don’t register Eureka with itself (setting in local.properties)
- Once up we can launch UI in localhost:{port} and see what is registered with Eureka
- For a microservices to register with Eureka: import start-netflix-eureka-client
- “Add the dependency is all you need to connect with Eureka”
Load Balancing
- In the Feign proxy interface, if we do not specify a url:
- Feign will talk to Eureka and pick up the instances of service and do load balancing automatically (step 22 -148)
- spring cloud starter load balancer is a dependency imported from eureka dependency
Spring cloud API Gateway
- An application could have hundreds of microservices and they have similiar features like authentication, authorization, logging, rate limiting, monitoring
- API gateway is solution and Spring cloud gateway is recommended dependency
- It is its own microservice with eureka and gateway dependency (step 22–149)
- you can implement all the common features in API gateway and the API gateway would take care of the common features and invoke the intented microservice (step23)
- “entry point” to your backend
- Custom Routes
- Create configuration class to redirect incoming request to url
- to find url from naming server use lib:// (step 24 9:00)
- You can match request by url or base on query, etc
- Logging Filter
- You can have a separate class only to filter all request and log them out (step 25)
Resilience4j (Circuit Breaker)
- When one microservice depend on another like a chain, if one of them in the middle is down or slow it will affect others depend on it
- It is its own microservice
- If one microservice is having problem, instead of keep hitting it with request, return some default result back
- retry
- Have a retry annotation default retry 3 times if any exception happen, if 3 times all failed only then it will return an error back
- To control retry behavior, configure setting in local.properteis (step 27 5:25)
- allow waiting time between retry and exponential waiting
- retry annotation also take in a fallback method
- circuit breaker
- Have a circuit breaker annotation (step 28)
- if a response is failing repeatedly, it return a default respond instead of calling the dependency
- a circuit breaker can be a 3 states, close, open, half open
- close state (no problem, always be calling the dependency)
- open state(service down, directly return default)
- half open(send a percentage of request)
- to move from open to half open, there is a wait duration setting
- if half open request success go back to close state, other wise go to open state
- Rate limiting
- there is a rate limiting annotation
- configure the limit in local.properties (step 29 2:10)
- the request over the rate limit will get an error
- BulkHead
- how many concurrent calls are allow
- there is a bulkhead annotation
- change the concurrent call number in local.properteis (step 29 4:52)
Web Service
- Definition: Software designed to support interoperable machine-to-machine interaction over a network
- service definition should define
- request responses format
- request structure
- response structure
- endpoint
- transport define how a service is called
- over HTTP or MQ (queue)
SOAP (simple object access protocol)
- restriction on format of xml that is exchange between service provider and service consumer
- soap define a specific xml request and response structure
- must have an envelope, header and body structure
- no restuction on transport, can use http or MQ
Restful (Representation State Transfer)
- A term coined by Roy Fielding, the person who developed http protocol
- architecture style
- Make the best use of http, use http to define the header and body, use http status code
- think in term of resources, define resources using concept already exist in http
- no restriction on data exchange format
- Must use HTTP for transport
JPA (Java Persistent API)
- Map Java object to SQL entry
- Without JPA, JDBC requires you to write query and write preparedStatement, which is difficult to maintain when table change
- JPA uses annotations like @Inheritance, @ManytoMany to map object to table
- JPA define the annotations and specify relationship. Hibernate provides the implementation.
Entity
- require a default no paramter constructor
Service
- a class to manage entity (save entity etc)
- Whenever we want to interacte with the database we need to be inside a transaction
- entityManager persist object
CommandLineRunner
- auto run by Spring as app start
- has a run method that we can do the insert action
Repository
- service is too repetitive if you have many entity ( similiar insert logic)
- repository is an interface that JPA will provide the implementation
- provide save() findbyId() method etc
- replace service
Restful web service
- start a spring project at start.spring.io
- Some useful dependencies
- Spring Web
- Spring Boot DevTools
- Spring Data JPA
- H2 Database (in memory database)
Controller
- controller handle http request (map method)
- use annotation like @RequestMapping(method = RequestMethod.GET, path = “/helloWorld”
- there is a short version: @GetMapping(path = x)
- To return an object(bean) in api response, the class must have getter for its property
- dispatcher servlet find the right controller to execute a request
- ResponseEntity response a status code (Step10)
- throw a exception with annotation to reurn error status like 404
- create a class extends from
ResponseEntityExceptionHandler
to make all controller return standard error response (Step12)
Validation
- check input is correct when calling api
- add annotation like @Size @Past
- In order to give api consumer useful message with validation fail, override the method handleMethodArgumentNotValid from ResponseEntityExceptionHandler (step15)
HATEOAS (Hypermedia as the Engine of Application State)
- make the api return data as well as return different actions we can perform on the data
- client make a request, and the next steps are handed to them in the response
- provides additional links to the request along with the response
- hard to maintain a list of links if we manually hard code them
- return EntityModel of <data> (step 15 5:25)
Internationalization (i18)
- customize language base on country
- during request, api cosumer can specify the language in header
- Accept-Language: fr
- add a new paramter call “locale” in controller method
- to avoid passing in locale in all parameter, we can read locale directly in LocaleContextHolder
- pick value in property files instead of hard coding response
- use messageSource to return value from property file
Content Negotiation
- specify return xml or json response
- api consumer speciy in header
- Accept: Application/xml
- automatically handle by spring boot when adding dependency com.fasterxml.jackson.dataformat
Swagger
- documentation that is automatically generated from code, to avoid maintance
- add dependency springdoc-openapi-ui
- type localhost:8080/swagger-ui.html
Actuator
- use for monitoring purpose, expose a bunch of url
- implement services that return response to these url
HAL Explorer
- provide a UI to navigate through the HATEOS and actuator links
Filtering
- When return a object from Get Request, we can filter some fields using @JsonIgnore on the field or on the class
- For dynamic filtering(filter different combinations of fields in different request), we can define MappingJacksonValue mapping
- step 25 (4:01)
Versioning
- Create two versions of the same service — step 27 (1:30)
- a basic way is to having different url for the request, call uri versioning
- another way is let client pass in a parameter, call request parameter versioning
- can use header parameter as well, call header versioning
- use the produces paramter (5:04). call accept header versioning / mime type versioning
- header versioning are harder to document because they are not automatically generted by swagger
Authentication
- Spring boot provided a basic security dependency
- When using it, change authenticaion to basic authentication and pass in the password copied from log
- change to custom password in local.properties
Richardson Maturity Model
- how restful is your service
- level 0: Expose SOAP web services in rest style
- level 1: Expose resources with proper URI
- level 2: level 1 + http protocal
- level 3: level 2 + HATEOAS
Web Service Best Practice
- Consumer first (documente help)
- make best use of http
- use http response code status
- No secure Info in URL
- Use Plurals
- Use nouns for resources (For exceptions, define a consistent approach)
Microservices
- Style to developmening a single application as a suite of small services
- These services are independently deployable
- REST
- Small well chosen deployable unit
- cloud enabled (have multiple deployed instance of the same service)
Advantage
- Adapte new technology and process easily
- Each microservices can be built with different technoloy
- Dynamic Scaling
- Faster release cycles
- because we are developing smaller component
Challenge
- Bounded Context
- How to identity the boundary for each micro services?
- it is an evolutionary process base on the knowledge we have at that time
- Configuration managment
- multiple instance & enviornment
- Dynamic scale up and down
- Visibility
- How to locate bug when you have so many micro services
- Pack of cards
- If one microservice go down, all the other micro services that depend on it also go down
Spring Cloud
- Spring cloud provides solution to the challenges above
- Configuration managment
- Spring Cloud Config Server
- Store all configuration in a git repo and SpringCloudConfigServer will expose the config to the services
- Dynamic scale up and down
- Ribbon Load Balancing
- distrubte load among all services
- Naming Server has 2 important feature
- all microservices register with the naming server
- provide url of the available instance of services for service
- Visibility and monitoring
- Ziplin Distributed Tracing
- trace a request across multiple components
- Netflix API Gateway
- Don’t have to implement basic features like logging in every microservice
- Fault tolerance (Pack of cards)
- Hystrix
- Configure a default response when a service is down
Microservices with spring cloud
- Give your microservice a good name in local.properties
- spring.application.name=””
- server.port=8888
Pick up value from application.properties
- Create a configuration class with @ConfigurationProperties
Spring Cloud Config Server
- it is its own microservice
- Have a folder with a bunch of local.properties files and trcked by git
- Have this config server microservice point to this folder with:
- spring.cloud.config.server.git.uri = file:///{}path (yes 3 / ) (step6)
- on localhost:8888/limits-service/default we can see the local.properties files value
- On the micro service who want to use this config server (step7)
- Define config client dependency in spring.io
- or import spring-cloud-starter-config in xml
- on local.properties
- spring.config.import=optional:configserver:http://localhost:8888
- To support dev / qa / prod env configs, name the git file limits-service-dev.properties (step8)
- on localhost:8888/limits-service/dev we can see the local.properties files value
- on limit microservice set local.propertiesspring.profiles.active=dev
- and spring.cloud.config.profile=dev
Setting up Dynamic Port in the Response
- We can run multiple instances of the same microservices by specifying the port number in IDE’s Run Configurations
- (Step 12 4:16) Go to VM arguments -Dserver.port=8001., will override what is in application.properties
- There is a class call Enviornment that we can get the port and pass back in response if needed
Feign
- To call one microservice from another microservice
- Without Feign: return a RestTemplate with the other service’s url (step 17 4:59)
- (step 18) Create a Proxy interface and just call the method of that proxy in controller
Eureka Naming Server (Service Registery)
- For different instances of the microservices, we don’t want to hard code the url:port because they might went down
- This naming server itself is another microservices (Step 19)
- Don’t register Eureka with itself (setting in local.properties)
- Once up we can launch UI in localhost:{port} and see what is registered with Eureka
- For a microservices to register with Eureka: import start-netflix-eureka-client
- “Add the dependency is all you need to connect with Eureka”
Load Balancing
- In the Feign proxy interface, if we do not specify a url:
- Feign will talk to Eureka and pick up the instances of service and do load balancing automatically (step 22 -148)
- spring cloud starter load balancer is a dependency imported from eureka dependency
Spring cloud API Gateway
- An application could have hundreds of microservices and they have similiar features like authentication, authorization, logging, rate limiting, monitoring
- API gateway is solution and Spring cloud gateway is recommended dependency
- It is its own microservice with eureka and gateway dependency (step 22–149)
- you can implement all the common features in API gateway and the API gateway would take care of the common features and invoke the intented microservice (step23)
- “entry point” to your backend
- Custom Routes
- Create configuration class to redirect incoming request to url
- to find url from naming server use lib:// (step 24 9:00)
- You can match request by url or base on query, etc
- Logging Filter
- You can have a separate class only to filter all request and log them out (step 25)
Resilience4j (Circuit Breaker)
- When one microservice depend on another like a chain, if one of them in the middle is down or slow it will affect others depend on it
- It is its own microservice
- If one microservice is having problem, instead of keep hitting it with request, return some default result back
- retry
- Have a retry annotation default retry 3 times if any exception happen, if 3 times all failed only then it will return an error back
- To control retry behavior, configure setting in local.properteis (step 27 5:25)
- allow waiting time between retry and exponential waiting
- retry annotation also take in a fallback method
- circuit breaker
- Have a circuit breaker annotation (step 28)
- if a response is failing repeatedly, it return a default respond instead of calling the dependency
- a circuit breaker can be a 3 states, close, open, half open
- close state (no problem, always be calling the dependency)
- open state(service down, directly return default)
- half open(send a percentage of request)
- to move from open to half open, there is a wait duration setting
- if half open request success go back to close state, other wise go to open state
- Rate limiting
- there is a rate limiting annotation
- configure the limit in local.properties (step 29 2:10)
- the request over the rate limit will get an error
- BulkHead
- how many concurrent calls are allow
- there is a bulkhead annotation
- change the concurrent call number in local.properteis (step 29 4:52)