This demo demonstrate Springboot microservices architecture with a car lease demo as an example.
The picture above is a simple representation of the microservice architecture.
Please note that User-Service, Car-Service and Customer-Service do not know how to handle user authorization. This is only done by the Auth-Service. The Auth-Service is able to extract the username from a security token. The username is then looked up in the database to obtain the user details such as user roles. These roles are returned to the Car-Service and are processed according to the role access. Below is explained with sequence diagram how the Car-Service can be accessed correctly.
For convenience, a simple sequence diagram is shown here to understand how the gateway redirects api calls with a token.
-
First the user must be signed in with username and password via the gateway. The api call is "POST: /api/v1/auth/signin".
-
The gateway redirect the call to one of the Auth-Service instances.
-
The Auth-Service has accepted the sign in and returns a security token.
-
The user wants to update the car details. The api call is then "PUT: /api/v1/car/{id}" and send it with the received security token in the HTTP header.
-
The gateway redirect the call to one of the Car-Service instances.
-
The car service needs to know if the user has access rights to update the car. So it sends an API call to the Gateway-Service "GET: /api/v1/auth/validatetoken/{token}".
-
The gateway redirect the api call to one of the Auth-Service instances.
-
The Auth-Service validates the token and returns the user id and roles to the Car-Service, if the token was extracted successfully.
-
The Car-Service now checks if the received user role contains "ROLE_BROKER". If it does, then returns the updated car details, otherwise returns an error message with HTTP status code "ACCESS DENIED".
Eureka Server
Eureka Server is an application that holds the information about all client-service instances. Every Micro service will register into the Eureka server and Eureka server knows all the client applications running on each port and IP address. Eureka Server is also known as Discovery Server.
All instances can be monitored on the Eureka server at:
http://localhost:8761
gateway-service
The gateway is a microservice that runs on port 9000. The gateway redirects all requests from the user to other instances.
The following path or end points are redirected to instances:
Path '/api/v1/user/**' -> User-service
Path '/api/v1/auth/**' -> Auth-service
Path '/api/v1/car/**' -> Car-service
Path '/api/v1/customer/**' -> Customer-service
Auth-Service
Multiple Auth-Service instances are running concurrently in the range of ports 4XXX.
User-Service
Multiple User-Service instances are running concurrently in the range of ports 8XXX.
Customer-Service
Multiple Customer-Service instances are running concurrently in the range of ports 6XXX.
Car-Service
Multiple Car-Service instances are running concurrently in the range of ports 7XXX.
This demonstration contains scripts that only works for Linux.
Docker MySQL is used to create the MySQL database. For this demonstration and simplicity of the demo, only one database server is used.
Run the script below to build Docker image for MySQL Database (you must install docker first on your machine before continue):
$ cd {project_path}/docker
$ mysql_docker.sh -b
Run the script below to run Docker image for MySQL Database (append -d to run detached):
$ cd {project_path}/docker
$ mysql_docker.sh -n
Run the script below to stop the Docker image if the database is running in detached mode:
$ cd {project_path}/docker
$ mysql_docker.sh -q
The database use default port 3306.
The default username is 'root' and the default password is 'super'. This file 'application.properties' also contains this username and password.
If you don't have Linux, then you can build docker image manually (you must install docker first on your machine before continue):
$ docker pull mysql:8.0
$ docker run --name mysql8 -p 3306:3306 -e MYSQL_ROOT_PASSWORD=super mysql:8.0
The database is now up and running.
Install OpenJDK 21:
$ sudo apt install openjdk-21-jdk
Follow below the instructions and run each java application in separate terminals.
$ cd {project_path}/eureka-server
$ ./gradlew clean
$ ./gradlew bootJar
$ java -jar build/libs/eureka-server-0.0.1-SNAPSHOT.jar
Open http://localhost:8761 on any browser. You should see all instances here. Check here later, once all instances are started.
$ cd {project_path}/gateway
$ ./gradlew clean
$ ./gradlew bootJar
$ java -jar build/libs/gateway-0.0.1-SNAPSHOT.jar
Open http://localhost:9000/actuator/gateway/routes on any browser. You should see all defined redirection paths.
Run three authentication-service instances, each with different port number:
$ cd {project_path}/services/authentication-service
$ ./gradlew clean
$ ./gradlew bootJar
$ SERVER_PORT=4001 java -jar build/libs/authentication-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=4002 java -jar build/libs/authentication-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=4003 java -jar build/libs/authentication-service-0.0.1-SNAPSHOT.jar
Run three user-service instances, each with different port number:
$ cd {project_path}/services/user-service
$ ./gradlew clean
$ ./gradlew bootJar
$ SERVER_PORT=8001 java -jar build/libs/user-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=8002 java -jar build/libs/user-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=8003 java -jar build/libs/user-service-0.0.1-SNAPSHOT.jar
Open http://localhost:8001/api/v1/user/greet on any browser.
Displays:
Welcome from 'USER-SERVICE'! ; Port: 8001
Open http://localhost:8002/api/v1/user/greet on any browser.
Displays:
Welcome from 'USER-SERVICE'! ; Port: 8002
Open http://localhost:8003/api/v1/user/greet on any browser.
Displays:
Welcome from 'USER-SERVICE'! ; Port: 8003
Open http://localhost:9000/api/v1/user/greet on any browser and refresh it several times. If you see different ports, then the gateway redirect to user-service instances correctly.
Displays:
Welcome from 'USER-SERVICE'! ; Port: 8001
or
Welcome from 'USER-SERVICE'! ; Port: 8002
or
Welcome from 'USER-SERVICE'! ; Port: 8003
Run three car-service instances, each with different port number:
$ cd {project_path}/services/car-service
$ ./gradlew clean
$ ./gradlew bootJar
$ SERVER_PORT=7001 java -jar build/libs/car-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=7002 java -jar build/libs/car-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=7003 java -jar build/libs/car-service-0.0.1-SNAPSHOT.jar
Open http://localhost:7001/api/v1/car/greet on any browser.
Displays:
Welcome from 'CAR-SERVICE'! ; Port: 7001
Open http://localhost:7002/api/v1/car/greet on any browser.
Displays:
Welcome from 'CAR-SERVICE'! ; Port: 7002
Open http://localhost:7003/api/v1/car/greet on any browser.
Displays:
Welcome from 'CAR-SERVICE'! ; Port: 7003
Open http://localhost:9000/api/v1/car/greet on any browser and refresh it several times. If you see different ports, then the gateway redirect to user-service instances correctly.
Displays:
Welcome from 'CAR-SERVICE'! ; Port: 7001
or
Welcome from 'CAR-SERVICE'! ; Port: 7002
or
Welcome from 'CAR-SERVICE'! ; Port: 7003
Run three customer-service instances, each with different port number:
$ cd {project_path}/services/customer-service
$ ./gradlew clean
$ ./gradlew bootJar
$ SERVER_PORT=6001 java -jar build/libs/customer-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=6002 java -jar build/libs/customer-service-0.0.1-SNAPSHOT.jar
$ SERVER_PORT=6003 java -jar build/libs/customer-service-0.0.1-SNAPSHOT.jar
Open http://localhost:6001/api/v1/customer/greet on any browser.
Displays:
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6001
Open http://localhost:6002/api/v1/customer/greet on any browser.
Displays:
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6002
Open http://localhost:6003/api/v1/customer/greet on any browser.
Displays:
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6003
Open http://localhost:9000/api/v1/customer/greet on any browser and refresh it several times. If you see different ports, then the gateway redirect to user-service instances correctly.
Displays:
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6001
or
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6002
or
Welcome from 'CUSTOMER-SERVICE'! ; Port: 6003
Swagger-UI:
Open http://localhost:xxxx/swagger-ui/index.html
if credential are required:
Username: root
Password: secret
H2-Database Console, if H2-Database is used:
Open http://localhost:xxxx/h2-console
Click on "Connect"
jdbc url: jdbc:h2:mem:testdb
Password is blank for now
#TODO
- Fine tuning business logic on all services.
- Add Session manager