Spring Boot Microservice Architecture Part 1
This article aims to help you understand Java Spring Boot Microservice Architecture so you can use it in any application. This article covers the pertinent Services, Frameworks, and Configurations needed to create a contemporary Microservice Application.
Architecture Basics
Spring Boot is a Java Framework which simplifies to create stand-alone, productions-grade running Applications. Spring Cloud provides tools for building common patterns in distributed systems. Both Frameworks enable easy implementation of lightweight Microservices and facilitate extensibility, changeability and interchangeability.
In the source code and in production, Microservice Architecture divides each service as a module. Each service is kept as a distinct application that may operate independently of the others. This implies that extremely loaded areas of the program may be readily scaled up and/or maintained by multiple teams.
Individual functionality’ responsibilities are maintained independent and modular by dividing Microservices into 5 levels. More information on Microservice Layer Architecture may be found here.
Each Microservice should be implemented as its own independent module as a Docker container. This enables optimal use of resources, because you can define in a Container what exactly the Service requires to run (Ports, Protocolls, Sockets, CPUs, Memmory, ..) to avoid waste of other ressources from the Server and to improve the security (Configuration files, Credentials, Secrets will be unaccessible even from the same Server). Furthermore a Docker Container is more reliable, because a container will work exactly in same way on any other Systems (e.g. development/production environments/machines).
Because you can define for the Container the resouces that to run optimal the Service requires to run optimal
Initial Spring Boot Microservice
Create a new Project via start.spring.io or through Intellij Spring Initializr with the required dependencies.
- Discovery Service (Eureka Discovery Client)
- Internal / External Communication (OpenFeign)
- Developer Tools (Lombok & Spring Boot DevTools)
- Presentation Layer (Spring Web)
- Persistence Layer (Spring Data JPA)
And then configure application properties like an application name, port and data source.
If the Database at the moment is not available you can add in-memory Database (H2).
Discovery Service
All Services register in Discovery Service with their addresses. This achieves the following:
- proof of heartbeat from all registered services
- distributing the query load to scaled services
- services are requested by name and not by address
- scaling the services require s no additional effort
Spring Cloud Netflix includes a Service Discovery (Eureka) pattern.
Configuration Server
- Create Discovery Server via start.spring.io or through Intellij Spring Initializr with Eureka Server dependency.
- Add @EnableEurekaServer Annotation to Spring Boot Application class
- Apply the following configurations to application.yml (demoDiscoveryServe > resources > application.yml):
eureka:
client:
fetch-registry: false
register-with-eureka: false
The both attributes are set to false because the Eureka Server does not need to register with itself and to read/update the entries to the registry e.g. for own heart beat.
Configuration Client
Apply the following configurations to Microservices in application.yml (DemoMicroservice > resources > application.yml):
eureka:
client:
service-url:
defaultZone: http://localhost:9999/eureka
Property defaultZone should contain Eureka Server Host-Address with path /eureka
Start Discovery Server and the Microservices and you will find now in Eureka UI (default url: localhost:8761, demo url: localhost:9999) all registered Services
API Gateway
For the communication between the whole Application with the outside world is API Gateway the best solution, it works like a link between the Microservices of the Application and external clients. Spring Cloud Gateway provides a library for building an API Gateway on top of Spring WebFlux.
On the one hand, this results in cleaner code because a genuine service address no longer has to be placed into the program code, but it also allows access to the operations of the Discovery Service and all those below Microservices to be controlled.
Configuration
- Create API Gateway Service via start.spring.io or through Intellij Spring Initializr with Spring Cloud Routing Gateway and Eureka Discovery Client dependency.
- Apply the following configurations to API Gateway Service in application.yml (DemoApiGateway > resources > application.yml):
spring:
application:
name: demo-api-gateway
cloud:
gateway:
routes:
- id: demo-microservice
uri: lb://DEMO-MICROSERVICE
predicates:
- Path=/**
server:
port: 9090
eureka:
client:
service-url:
defaultZone: http://localhost:9999/eureka
Property gateway.routes.id defines the resource path to access configured resource in gateway.routes.uri and the uri is id of service that registered in Eureka Server (it should be in upper case)
After being registered with Eureka, the API Gateway may now access services using application name, and route setup for DNS or IP addresses is no longer required. One advantage is that the services are secure, and another is that when a service is scaled, no further configuration is necessary.
Services are now accesable trough http://localhost:9090/demo-microservice/ (<API-Gateway-Host-Adresse>/<my-route-path-to-microservice>/<Ressource-Path>)
Internal / External Communication
Microservices are usually only individual modules of an entire application, internal communication between the Microservices is most necessary to provide the whole business case. Furthermore, it is common to communicate with 3rd party applications. Spring Cloud OpenFeign is an abstraction over REST-based calls and adds support on requests or responses in a declarative way with build in REST-Client.
Configuration
- Add OpenFeign dependency to Spring Boot Application (to Service that requires internal or external REST-Communication to other Services)
- Add @EnableFeignClients Annotation to Spring Boot Application class (DemoOpenFeign > DemoOpenFeignApplication.java):
3. Create Client Interface (DemoOpenFeign > ExternalServiceClient.java / DemoOpenFeign > InternalServiceClient.java) with @FeignClient(name = “client_service_name”, url = “client_url”) Annotation. For more information about package structure see the folowing article: Java Microservice Layer Architecture
and then define CRUD methods with request mapping to internal or external Service (request methods should match with the implementation of requested Client resource)
Now you can inject the created Bean into your Service and make REST calls to the external or internal Services (DemoOpenFeign > OpenFeignController.java):
Summary
All in all, we have created a solid blueprint for a Microservice Architecture. In the real-world scenario, there is much more that depends to a Microservice Ecosystem, such as
- API Documentation
- Config Server
- Logging and Monitoring
- Troubleshooting
- Fault Tolerance
- …
All examples described in the article are available on GitHub.
Have fun and happy coding :)