> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring Boot & Microservices

> Build production-grade microservices with Java, Spring Boot, and Spring Cloud

# Spring Boot & Microservices Master Course

> **Spring Boot** is the de-facto standard for building Java-based backend applications. Combined with **Spring Cloud**, it provides a powerful toolkit for building resilient, scalable, and cloud-native microservices.

This course takes you from "Hello World" to deploying a complex mesh of microservices, covering all the patterns expected in senior technical interviews and modern production systems.

Think of this journey like building a city. Spring Boot gives you the ability to construct individual buildings quickly (each microservice). Spring Cloud provides the roads, traffic lights, power grid, and emergency services that let those buildings function as a cohesive city. Without the infrastructure, you just have isolated structures. Without the buildings, the infrastructure has nothing to connect.

***

## Why this Course?

<CardGroup cols={2}>
  <Card title="Industry Standard" icon="building">
    Used by 70% of Fortune 500 companies for their backend infrastructure.
  </Card>

  <Card title="Microservices First" icon="network-wired">
    Focuses heavily on distributed systems patterns, not just basic APIs.
  </Card>

  <Card title="Production Ready" icon="shield-check">
    Learn observability, resilience, and security patterns essential for real-world ops.
  </Card>

  <Card title="Cloud Native" icon="cloud">
    Designed for deployment on Docker and Kubernetes from Day 1.
  </Card>
</CardGroup>

## Course Roadmap

<Steps>
  <Step title="Spring Boot Fundamentals">
    From `public static void main` to dependency injection, auto-configuration, and your first REST API.
  </Step>

  <Step title="Data Persistence">
    Master Spring Data JPA, Hibernate, transaction management, and database migrations.
  </Step>

  <Step title="Microservices Architecture">
    Break the monolith. Learn Service Discovery, API Gateways, and Distributed Configuration.
  </Step>

  <Step title="Resilience & Observability">
    Implement Circuit Breakers, Distributed Tracing (Zipkin/Jaeger), and Monitoring (Prometheus/Grafana).
  </Step>

  <Step title="Event-Driven Systems">
    Decouple services using Apache Kafka and RabbitMQ with Spring Cloud Stream.
  </Step>

  <Step title="Capstone Project">
    Build a complete E-Commerce Microservices ecosystem with 4+ communicating services.
  </Step>
</Steps>

## Prerequisites

* **Java Proficiency**: You should know Java (Fundamentals, OOP, Collections) fairly well. Check out our [Java Crash Course](/courses/java-crash-course/overview) if you need a refresh.
* **Basic SQL**: Understanding of tables, joins, and PK/FK relationships.
* **Terminal Basics**: Comfortable navigating folders and running commands.

***

## The Tech Stack

| Component      | Technology                                 |
| :------------- | :----------------------------------------- |
| **Language**   | Java 17+ (LTS)                             |
| **Framework**  | Spring Boot 3.x, Spring Cloud              |
| **Database**   | PostgreSQL, H2 (for dev)                   |
| **ORM**        | Spring Data JPA (Hibernate)                |
| **Gateway**    | Spring Cloud Gateway                       |
| **Discovery**  | Netflix Eureka / Spring Cloud LoadBalancer |
| **Resilience** | Resilience4j                               |
| **Monitoring** | Micrometer, Prometheus, Zipkin             |
| **Messaging**  | Kafka / RabbitMQ                           |
| **Container**  | Docker                                     |

**A senior engineer would note:** This stack closely mirrors what Netflix, Uber, and most Fortune 500 companies run in production. The specific tools may vary (Consul instead of Eureka, Istio instead of Spring Cloud Gateway), but the **patterns** -- service discovery, circuit breaking, distributed tracing, externalized config -- are universal. Master the patterns, and switching tools is straightforward.

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="When would you recommend staying with a monolith instead of moving to microservices?">
    **Strong Answer:**

    * The right answer is almost always "start with a monolith." Microservices are not an upgrade from monoliths -- they are a trade. You give up simplicity, single-process debugging, and transactional consistency in exchange for independent deployability and team autonomy. If your team is under 20 engineers and your domain boundaries are still shifting, microservices will slow you down, not speed you up.
    * Shopify runs one of the largest Rails monoliths in existence and processes billions in GMV. They modularized internally (components, engines) rather than splitting into services. The key insight is that you can get 80% of the organizational benefits of microservices by enforcing module boundaries within a monolith -- without paying the distributed systems tax.
    * The real trigger for microservices is organizational, not technical. When two teams cannot deploy independently because they share a codebase and a deployment pipeline, and the merge conflicts and release coordination overhead are measurably hurting velocity -- that is when you split. Conway's Law drives architecture more than any technical concern.
    * A common anti-pattern I have seen: teams split into microservices prematurely, then end up with a "distributed monolith" -- services that must be deployed together because they share a database or have synchronous call chains five services deep. That is strictly worse than a monolith because you now have network failure modes with none of the independence benefits.

    **Follow-up: How do you identify the right service boundaries when you do decide to split?**

    This is where Domain-Driven Design earns its keep. You identify Bounded Contexts -- areas of the domain where a particular model and its ubiquitous language are consistent. The "User" in your billing system (has payment methods, invoices, credit limits) is fundamentally different from the "User" in your support system (has tickets, SLA tiers, satisfaction scores). That semantic boundary is your service boundary. Practically, I look at the data: if two modules rarely share writes to the same tables, that is a strong candidate for a split. If they constantly join across each other's tables, forcing a split will create a distributed join nightmare that performs 10x worse than the original query.
  </Accordion>

  <Accordion title="Walk me through what happens when you call SpringApplication.run(). What does the framework do before your first controller is ready to handle a request?">
    **Strong Answer:**

    * First, Spring creates and configures the `Environment` object, which resolves all property sources -- system env vars, application.yml, command-line args, config server -- and merges them in the documented precedence order. This is why your `SPRING_DATASOURCE_URL` environment variable overrides what is in application.yml.
    * Next, it publishes an `ApplicationEnvironmentPreparedEvent`, which is how Spring Cloud Config hooks in -- the config client fetches remote properties before the ApplicationContext even starts building beans. This is the "bootstrap" phase.
    * Then it creates the `ApplicationContext` (usually `AnnotationConfigServletWebServerApplicationContext` for web apps), which triggers component scanning. Spring reads `@ComponentScan` from your main class and walks the package tree, building `BeanDefinition` objects for every `@Component`, `@Service`, `@Repository`, `@Controller` it finds. At this point, no beans are instantiated yet -- just their definitions are registered.
    * Auto-configuration kicks in via `@EnableAutoConfiguration`. Spring reads the `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` file (or the older `spring.factories`), loads every listed configuration class, and evaluates their `@Conditional` annotations. If `DataSource.class` is on the classpath and no `DataSource` bean is already defined, it auto-configures one. This is the "magic" -- it is just conditional bean registration.
    * Finally, it creates the embedded web server (Tomcat by default), registers the `DispatcherServlet`, starts listening on port 8080, and publishes `ApplicationReadyEvent`. Only then is your controller reachable.

    **Follow-up: A developer adds a library that bundles an auto-configuration, and suddenly the app behavior changes unexpectedly. How do you diagnose and fix it?**

    Start with `--debug` flag or `debug=true` in application.properties. This prints the Conditions Evaluation Report at startup, showing every auto-configuration class that was positively matched or negatively matched, and the exact condition that triggered it. You will see something like "DataSourceAutoConfiguration matched because DataSource.class was found on the classpath." From there, you can either exclude the auto-configuration explicitly with `@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)` or define your own bean of that type so `@ConditionalOnMissingBean` prevents the auto-configured one from being created. The broader lesson: always audit transitive dependencies. A single library pulling in `spring-boot-starter-data-jpa` transitively can trigger an entire database auto-configuration you never asked for.
  </Accordion>

  <Accordion title="Your company runs 30 Spring Boot microservices in production. A new VP of Engineering proposes migrating everything to a service mesh like Istio and removing Spring Cloud entirely. How do you evaluate this?">
    **Strong Answer:**

    * This is a classic "library vs. infrastructure" debate. Spring Cloud implements patterns like service discovery, circuit breaking, and load balancing at the application level -- inside your JVM. A service mesh like Istio implements the same patterns at the infrastructure level -- via sidecar proxies (Envoy) injected into every pod. Both solve the same problems, but the operational model is completely different.
    * The advantage of Istio: language-agnostic. If your 30 services are all Java, Spring Cloud works great. But the moment you add a Python ML service or a Go data pipeline, those services cannot use Spring Cloud libraries. A service mesh gives you uniform observability, mTLS, and traffic management across all languages without changing application code.
    * The disadvantage: operational complexity. Istio adds a control plane (istiod), sidecar proxies to every pod (doubling your container count), and a steep learning curve. I have seen teams spend 3-6 months just getting Istio stable in production. If your team does not have dedicated platform engineers, this is a significant risk.
    * My recommendation would be incremental: keep Spring Cloud for application-level concerns (Feign clients, config management, Spring Security), but adopt the mesh for infrastructure concerns (mTLS, traffic splitting for canary deploys, cross-language tracing). They are not mutually exclusive. Specifically, I would drop Eureka in favor of Kubernetes-native service discovery first (since K8s Services already do DNS-based discovery), then evaluate whether the mesh's circuit breaking replaces Resilience4j for your use cases.

    **Follow-up: What specific metric or signal would tell you the migration is actually improving things versus adding complexity?**

    Deployment frequency and change failure rate -- the DORA metrics. If moving to the mesh means teams can deploy more often with fewer incidents (because mTLS catches misconfigured service-to-service auth, canary deploys catch regressions early), then it is paying for itself. If deployment frequency drops because engineers are now debugging Envoy sidecar misconfigurations instead of shipping features, you have traded one form of complexity for a worse one. I would also track P99 latency before and after -- each sidecar hop adds 1-3ms, and in a call chain 5 services deep, that compounds to 10-15ms of pure proxy overhead.
  </Accordion>
</AccordionGroup>
