MicroservicesFundamentalsbeginner
Updated:

Microservices Architecture Explained

6 min read

See how the pieces fit: services, API gateway, discovery, per-service databases and messaging. A clear, example-driven tour of microservices architecture.

TL;DR – Quick Answer

Microservices architecture structures an application as a set of small services, each owning one business capability and its own database, communicating over the network. Requests enter through an API gateway, which routes them to services located via service discovery. Services talk synchronously with REST or asynchronously through a message broker, and each is deployed and scaled independently.

On This Page

A microservices application looks intimidating on an architecture diagram — boxes for services, gateways, registries, databases and brokers, with arrows everywhere. But every one of those boxes exists to solve a specific problem created by splitting an app into independent pieces. Once you know which problem each component solves, the whole diagram reads like a sentence. This tutorial walks the components in the order a request actually flows through them.

If the very idea of microservices is still new, read what are microservices first. Here we go one level deeper into how the parts connect into a working system.

The shape of the system

At the highest level, a request travels like this: a client hits the API gateway, which authenticates it and routes it to the right service; that service finds any other services it needs through service discovery; each service reads and writes its own database; and services that do not need an immediate reply talk through a message broker. Every component below maps to one of those steps.

Component Problem it solves
Services Split business capabilities into independent, deployable units
API gateway Give clients one entry point; centralise auth and routing
Service discovery Let services find each other when addresses keep changing
Per-service database Keep services independent by isolating their data
Message broker Decouple services that communicate asynchronously
Config server Manage configuration across many services centrally

Services: one capability each

The building block is the service itself. Each one owns a single business capability — orders, inventory, payments, notifications — and nothing more. This focus is what lets a small team fully own a service and deploy it on its own schedule.

Here is a minimal order service endpoint in Spring Boot. It exposes one capability over REST and knows nothing about how inventory or payments are implemented internally:

import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/orders")
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    @PostMapping
    public OrderResponse placeOrder(@RequestBody OrderRequest request) {
        Order saved = orderService.placeOrder(request);   // owns only order logic
        return OrderResponse.from(saved);
    }
}

The key idea is the boundary: this service exposes what it does (place an order) and hides how. If you already know Spring Boot REST controllers, a service is just a small, focused Spring Boot app with a clear responsibility.

API gateway: the single front door

If clients had to know the address of every service, adding or moving a service would break every client. The API gateway solves this by being the one address clients talk to. It receives every external request and routes it to the correct internal service.

Because all traffic flows through it, the gateway is also the natural home for cross-cutting concerns: authentication, rate limiting, and request logging happen once, at the edge, instead of being duplicated in every service. A Spring Cloud Gateway route is as simple as declaring which path goes to which service:

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://order-service       # lb = look up via service discovery
          predicates:
            - Path=/orders/**
        - id: inventory-service
          uri: lb://inventory-service
          predicates:
            - Path=/inventory/**

Notice lb://order-service — the gateway does not hardcode an IP. It asks service discovery for the current address, which brings us to the next component. The API gateway deep dive covers this piece in full.

Pro tip: Do not put business logic in the gateway. Its job is routing and cross-cutting concerns only. The moment the gateway starts making order-specific decisions, it becomes a bottleneck that every team must coordinate through — the exact coupling microservices are meant to avoid.

Service discovery: finding moving targets

In the cloud, service instances are created and destroyed constantly as the system scales up and down, and their IP addresses change every time. Hardcoding addresses is hopeless. Service discovery solves this: each service registers itself with a registry (such as Eureka or Consul) when it starts, and callers look services up by name.

So when the gateway wants order-service, it asks the registry "where is order-service right now?" and gets back the address of a healthy instance. If three instances of the order service are running, the registry helps distribute calls across them. This is what makes independent scaling actually work — you add instances and the rest of the system finds them automatically.

Databases: one per service

Each service owns its own database, and no other service touches it directly. This is a deliberate constraint, and it is the heart of what makes services independent. The order service can change its schema, switch from MySQL to PostgreSQL, or restructure its tables, and no other service notices, because none of them read its tables.

The cost is that you can no longer wrap a single transaction around changes in two services. Keeping data consistent across services requires patterns like the saga, and understanding that trade-off is central to the whole style — the microservices vs monolith comparison digs into why teams accept it.

Messaging: decoupling in time

Synchronous REST calls are simple but couple services in time — if the inventory service is down when the order service calls it, the order fails. A message broker breaks that coupling. The order service publishes an "order placed" event and moves on; the inventory service consumes the event whenever it is ready, even if it was briefly down.

This asynchronous style improves resilience and lets one event fan out to many consumers — inventory, analytics and notifications can all react to the same "order placed" event independently. The trade-off is eventual consistency: the inventory is not updated the instant the order is placed, but a moment later. The Apache Kafka basics page shows how a broker actually delivers those events.

Common mistake: Making every call asynchronous "for decoupling." Some operations genuinely need an immediate answer — checking stock before confirming an order, for instance. Use synchronous calls when the caller must wait for the result, and messaging when it can react later. Mixing them up leads to either fragile chains or needless complexity.

Supporting components

A production system adds a few more pieces around this core. A configuration server centralises settings so you do not redeploy every service to change a value. Observability tooling — metrics, logs and distributed traces — lets you understand a request that crosses many services, which is why teams weigh observability against plain monitoring. And security is applied at the edge and re-verified in each service. None of these are optional at scale; they are what turn a pile of services into an operable system.

Putting it together

Trace one request end to end to lock it in. A user submits an order. The API gateway authenticates the request and routes /orders to the order service, whose address it got from service discovery. The order service writes to its own database, then publishes an "order placed" event to the broker. The inventory service, discovered and running independently, consumes that event and updates its own database. Every component you met did exactly one job in that flow.

That mental model — request in through the gateway, routed via discovery, data in per-service databases, events over the broker — is the whole architecture. Everything else is refinement.

The fastest way to make this concrete is to build a two-service version yourself: an order service and an inventory service, a gateway in front, talking over both REST and a broker. That is precisely the project you build in the Java Full Stack with AI program at CodeBegun, and it turns this diagram into something you have actually run. From here, continue through the microservices learning path to go deeper on each component, and check your understanding against the microservices interview questions.

Frequently Asked Questions

What are the main components of a microservices architecture?
The core pieces are the services themselves, an API gateway as the single entry point, a service registry for discovery, per-service databases, and a message broker for asynchronous communication. Supporting components include configuration servers, monitoring, and security at the edge. Together they let many small services behave like one coherent application.
What does an API gateway do in microservices?
An API gateway is the single entry point for all external requests. It routes each request to the correct service and handles cross-cutting concerns like authentication, rate limiting and request logging. This keeps clients from needing to know the address of every individual service.
What is service discovery and why is it needed?
Service discovery lets services find each other without hardcoded addresses. Each service registers itself in a registry when it starts, and callers look up the current address by name. This is essential because in the cloud, service instances come and go and their IP addresses change constantly.
Why does each microservice have its own database?
Owning its own database makes a service truly independent, so it can change its schema and deploy without coordinating with others. If services shared a database, a change in one could break another, defeating the purpose. The trade-off is that consistency across services now needs patterns like the saga.
How do services communicate in this architecture?
Synchronously through REST or gRPC when an immediate response is needed, and asynchronously through a message broker like Kafka or RabbitMQ when work can happen in the background. Synchronous calls are simpler but couple services in time. Asynchronous messaging decouples them and improves resilience at the cost of eventual consistency.
Is Spring Boot good for building microservices?
Yes, Spring Boot with Spring Cloud is the most common way to build microservices on the JVM. It provides ready-made support for REST endpoints, service discovery, configuration and gateways. That is why most Java microservices job descriptions list Spring Boot and Spring Cloud.

Want to Build Your Career in Java Full Stack with AI?

Join CodeBegun and train with working industry engineers — Explore the Program

Apply for Demo Class →
Siva Prasad Galaba
Founder, CodeBegun · Staff Engineer

Founder of CodeBegun. 15+ years building Java systems at companies like Crunchyroll. Teaches Java, Spring Boot and system design the way the industry actually works, and mentors students through projects, mock interviews and placement preparation.

Technically reviewed by CodeBegun Technical TeamLast reviewed 15 July 2026 LinkedIn
Chat with us