- Lab
- Core Tech

Guided: Transitioning from Monolith to Microservices
In this hands-on Code Lab, you will break down a monolithic application into independent microservices. Using an e-commerce example from Globomantics, you will identify service boundaries, extract key functionality, and enable communication using REST APIs. By the end, you will have a working setup of services that run and interact independently.

Path Info
Table of Contents
-
Challenge
Introduction
Lab Overview
In this hands-on lab, you will work as a backend engineer at Globomantics, a growing e-commerce company. The current system is a monolithic application that combines all business domains such as product catalog, user management, and order processing into a single codebase. As the company scales, this architecture presents challenges in agility, scalability, and maintainability.
Your task is to decompose this monolith into independent microservices. Each service will run separately, communicate with others using REST APIs, and function independently.
By the end of this lab, you will have broken down the monolith and established inter-service communication through a guided, step-by-step approach that reflects a real-world migration process.
To help you focus on understanding the migration steps rather than setting up files from scratch, scaffolding has already been provided in each microservice. Blank files are in place to simplify the process, you can copy the relevant code from the monolith into the corresponding files within each microservice.
info>If you get stuck on a task, you can view the solution in the
solution
folder in your file tree, or click the Task Solution link at the bottom of each task after you've attempted it. -
Challenge
Understand the Monolith Architecture
In this step, you will examine the current structure of the monolithic application and understand the limitations that led to the decision to transition to microservices.
Monolithic Architecture:
You will observe that a monolithic architecture means the entire application is built and deployed as a single unit. All features such as user management, product catalog, and order processing reside in one codebase and run within the same runtime.
For example, the Globomantics monolithic application includes:
- A single Spring Boot application with one
@SpringBootApplication
main class running on a port (e.g.,8001
). - Package structure combining all domains within the same project.
- Shared resources, such as a common set of model classes (
User
,Product
, andOrder
) used across all features within the monolithic application. - Controllers such as
UserController
,ProductController
, andOrderController
, all exposed through the same base URL (e.g.,http://localhost:8001/users
,/products
,/orders
).
The structure of monolith:
monolith-app/ ├── src/main/java/com/globomantics/ │ ├── MonolithApplication.java │ ├── controller/ │ │ ├── OrderController.java │ │ ├── ProductController.java │ │ └── UserController.java │ ├── model/ │ │ ├── Order.java │ │ ├── OrderDetail.java │ │ ├── Product.java │ │ └── User.java │ └── service/ │ ├── OrderService.java │ ├── ProductService.java │ └── UserService.java
You will see that all components are tightly coupled and run as a single process. Any change or deployment affects the entire application.
Now you'll start the application and understand the APIs which it offers.
Limitations of the Monolith:
As you explore further, you will identify several drawbacks with this architecture:
- Limited Scalability: You cannot scale individual modules independently. Even if only the product catalog faces high demand, you will have to scale the entire application, which is inefficient.
- Slower Development and Deployment: A small change in one area, such as user registration, requires rebuilding and redeploying the whole application. This increases coordination overhead among teams.
- Fault Isolation: A single failure, for example in the
OrderController
, can crash the entire application since all components share the same runtime. - Technology Lock-in: You cannot mix and match technologies easily. Every part of the application must use the same tech stack.
- Long-Term Maintenance Issues: As the codebase grows, it becomes increasingly difficult to manage. Build times, testing scope, and risk of regressions all increase.
To overcome these challenges, the monolith is broken down into smaller, independently deployable services. Globomantics is moving to a microservices architecture, where each service is dedicated to a specific business capability and can be developed, deployed, and scaled independently. --- You now understand how the Globomantics monolithic application is structured and what limitations it introduces. You will proceed to identify logical service boundaries in the next step.
- A single Spring Boot application with one
-
Challenge
Identify Service Boundaries
In this step, you identify logical service boundaries in the monolithic application to guide its decomposition into microservices.
You will analyze the functionality within the monolith and group related features into distinct business domains. A good approach is to align these groupings with business capabilities or bounded contexts. In the Globomantics application, you clearly see three primary domains: Users, Products, and Orders.
Define the following microservices:
-
User Service: handles user registration, login, and profile management. It owns all user-related logic and data.
-
Product Service: manages the product catalog, including inventory, pricing, and descriptions.
-
Order Service: processes customer orders, manages order history, and interacts with the other two services to complete transactions.
Each service is aligned with a specific business function, making it easier to maintain, scale, and deploy independently. For example, product updates can now be handled without affecting the user or order systems.
In the monolith, the order functionality likely accessed product and user data directly through shared repositories. As part of the microservices transition, shift this interaction to service-to-service communication using REST APIs. Each service will now be responsible for its own data and expose the necessary endpoints to other services.
It's best to avoid using a shared database. Instead, assign data ownership to each microservice. While in this lab the persistence is simulated with in-memory collections, the principle remains important for avoiding tight coupling.
You have successfully identified the domain boundaries within the monolithic application and outlined the responsibilities for three microservices: User, Product, and Order. In the next step, you will begin extracting the Product service into its own standalone microservice.
-
-
Challenge
Extract Product Service
In this step you will extract the product related functionality from the monolith into a standalone microservice
product-service
. Navigate to theproduct-service/src/main/java/com/globomantics
folder in the FileTree section.The
ProductServiceApplication
class serves as the new entry point for the extracted product service, separate from the monolith.To run this service independently, assign it a unique port. Configure the product service to run on port
9001
.| Service | Port | |------------------|--------| | Monolith | 8001 | | Product Service | 9001 | | User Service | 9002 | | Order Service | 9003 | info> For simplicity, a plain class with in-memory data structures is used to store data. In real-world applications, this would typically be a JPA
@Entity
with appropriate annotations, and each service might use its own dedicated database based on the requirements. Next, you will set up dedicated Controller and Service classes for the Product service by copying them from the monolith.The
ProductService
class contains the business logic for product-related operations and will now be part of the standaloneproduct-service
. TheProductController
exposes REST endpoints for managing products and will now operate independently within theproduct-service
. Great job!Now that you've successfully created your first microservice, you'll move on to migrate the User and Order services next.
-
Challenge
Extract User Service
You will now extract the
user-service
from the monolith.Similar to the previous step, update the port for User Service to
9002
.In this step, you’ve successfully extracted the User Service into its own standalone microservice.
Next, you will extract the Order Service. Unlike the previous services, this step will also include inter-service communication, where the Order Service will interact with the Product and User services to fetch additional details.
-
Challenge
Extract Order Service
In this step, you'll extract the Order service and also configure the order service to communicate with Product and User service.
Next you will copy the contents of Controller , Model and Service class files. In addition to the
Order.java
model, you will also need to includeUser.java
andProduct.java
to represent the responses received from the respective microservices.The
OrderDetail.java
model will be used to structure the final response returned by the Order Service API. Now that you've copied all the classes, the final step is to set up inter-process communication, which you'll complete in the next step. -
Challenge
Enable Inter-Service Communication
In this step you will use
RestTemplate
in theorder-service
to fetch data from theuser-service
andproduct-service
using their respective URLs.RestTemplate
RestTemplate
is a synchronous client provided by Spring for making HTTP requests to external services. In a microservices architecture, it enables one service to call another over HTTP.The
RestTemplate
has been configured in theAppConfig.java
file and is available for use throughout the project. You will enhanceOrderService.java
to enable inter-service communication. Instead of returning just the raw order data, the Order Service will call the User Service and Product Service to fetch additional details based on theuserId
andproductId
in the order.Here’s how you can fetch the user details using
RestTemplate
:User user = restTemplate.getForObject(userServiceUrl + "/" + order.getUserId(), User.class);
You’ll use a similar approach to retrieve product details. These responses will be combined into an
OrderDetail
object, which will be returned by the API.Now you will first inject the
RestTemplate
in the Order Service.The
@Value
annotation in Spring is used to inject values from the application's configuration file i.eapplication.properties
directly into fields.Next you will replace the Product and User Services with their respective URLs. Now that the service URLs have been injected into the appropriate fields, you will use them to call the respective microservices. Great work!
The Order microservice is now set up. In the next step, you’ll verify its API endpoints to ensure everything is working as expected. -
Challenge
Test and Verify the Microservices Setup
Now that all three services (
product-service
,user-service
, andorder-service
) are configured to run independently, you will test their endpoints to verify they are working as expected and communicating correctly.Now you will ensure that all services are started. You should have five terminal windows open:
- Terminal 1: Monolith (
8001
) - Terminal 2: Product Service (
9001
) - Terminal 3: User Service (
9002
) - Terminal 4: Order Service (
9003
) - Terminal 5: For testing with
curl
Start each service in its respective terminal. This setup lets you manage and test the services independently.
info> You can keep the monolith stopped as you only want to test the microservices. To stop any running service, go to its terminal window and press
CTRL+C
. Great work !This confirms that your microservices are functioning independently and are able to interact with each other successfully.
- Terminal 1: Monolith (
-
Challenge
Conclusion and Next Steps
Conclusion
You successfully transitioned a monolithic Spring Boot application into a set of independent microservices. Along the way, you identified domain boundaries, extracted services, implemented full CRUD operations, and enabled inter-service communication using
RestTemplate
.By completing this lab, you demonstrated how to:
- Analyze and break down a monolithic architecture
- Design and implement domain-driven microservices
- Enable REST-based communication between services
Next Steps
- You can now add database support (e.g., H2, PostgreSQL) to each service for persistent storage.
- Explore using API gateways (e.g., Spring Cloud Gateway) to centralize request routing.
- Implement security between services using OAuth2 or JWT.
- Consider replacing
RestTemplate
withWebClient
or using service discovery tools like Eureka and Spring Cloud. - Add unit and integration tests to each service for production readiness.
This foundational setup prepares you to build scalable, maintainable, and cloud-ready microservice applications.
What's a lab?
Hands-on Labs are real environments created by industry experts to help you learn. These environments help you gain knowledge and experience, practice without compromising your system, test without risk, destroy without fear, and let you learn from your mistakes. Hands-on Labs: practice your skills before delivering in the real world.
Provided environment for hands-on practice
We will provide the credentials and environment necessary for you to practice right within your browser.
Guided walkthrough
Follow along with the author’s guided walkthrough and build something new in your provided environment!
Did you know?
On average, you retain 75% more of your learning if you get time for practice.