Spring Boot Tutorial

59 posts in this section

Reliable Event Publishing: The Transactional Outbox Pattern

There is a fundamental problem with publishing Kafka events after a database commit: if the application crashes between the commit and the publish, the event is lost forever. The Transactional Outbox Pattern solves this. The Problem @Transactional public Order createOrder(CreateOrderRequest request) { Order order = orderRepository.save(buildOrder(request)); // DB committed ✓ kafkaTemplate.send("order-events", event); // ← Crash here → event lost, DB already committed // → Inventory never updated, customer never notified return order; } Two distributed systems (PostgreSQL and Kafka) can’t be in a single transaction.

Continue reading »

Resilience Patterns with Resilience4j

In microservices, every network call can fail. A slow dependency can exhaust your thread pool, cascading into a full outage. Resilience4j provides the patterns to handle these failures gracefully — without hiding them. Setup <dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> Circuit Breaker A circuit breaker wraps a remote call. When failures exceed a threshold, the circuit “opens” and calls fail immediately (without waiting for a timeout) — protecting your thread pool and giving the failing service time to recover.

Continue reading »

Role-Based Access Control with @PreAuthorize

Roles and permissions control what authenticated users can do. This article implements a complete RBAC system — from URL-level rules to method-level security and resource ownership checks. Roles vs Permissions Roles are coarse-grained groupings (USER, MANAGER, ADMIN). Permissions are fine-grained actions (READ_ORDERS, WRITE_PRODUCTS, DELETE_USERS). Assign permissions to roles: ADMIN → all permissions MANAGER → READ_ORDERS, WRITE_ORDERS, READ_PRODUCTS, WRITE_PRODUCTS USER → READ_OWN_ORDERS, WRITE_OWN_ORDERS, READ_PRODUCTS Model permissions as a typed enum: public enum Permission { // Order permissions READ_ORDERS, WRITE_ORDERS, DELETE_ORDERS, READ_OWN_ORDERS, WRITE_OWN_ORDERS, // Product permissions READ_PRODUCTS, WRITE_PRODUCTS, DELETE_PRODUCTS, // User management READ_USERS, WRITE_USERS, DELETE_USERS } public enum Role { USER(Set.

Continue reading »

Service Discovery with Eureka

In a microservices environment, services scale up and down dynamically. You can’t hardcode IP addresses — a service running on 10 pods today has 10 different addresses. Service discovery solves this: services register themselves, and clients look up live instances by name. What Service Discovery Does Without service discovery: Order Service → http://192.168.1.45:8081/api/inventory ← hardcoded, breaks when IP changes With service discovery: Order Service → "inventory-service" → Eureka → [192.168.1.45:8081, 192.

Continue reading »

Spring AI: Build a RAG Application

Large language models know a lot — but not about your data. RAG (Retrieval-Augmented Generation) solves this: find the relevant context from your documents, inject it into the prompt, and let the model answer grounded in your data. This article builds a complete RAG API with Spring AI 2.0. What You’ll Build A Q&A API over your product documentation: User: "What's the return policy for electronics?" → Search vector store for relevant docs → Inject matching paragraphs into prompt → Claude/GPT answers based on your actual docs Without RAG: the LLM guesses or hallucinate your policy.

Continue reading »

Spring Bean Scopes and Lifecycle

Every bean in the Spring container has a scope (how many instances exist and for how long) and a lifecycle (what happens when it’s created and destroyed). Understanding these prevents subtle bugs and lets you optimize resource usage. Bean Scopes Overview Scope Instances Available in singleton One per ApplicationContext All apps prototype New instance every time All apps request One per HTTP request Web apps session One per HTTP session Web apps application One per ServletContext Web apps Singleton (Default) By default, every Spring bean is a singleton — one instance per ApplicationContext.

Continue reading »

Spring Boot Actuator: Health, Metrics, and Management Endpoints

A running application is not enough — you need to know if it’s healthy, how it’s performing, and what it’s doing. Spring Boot Actuator exposes that information through HTTP endpoints and metrics. Setup <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> By default, only /actuator/health and /actuator/info are exposed over HTTP. Everything else is available via JMX. Enable what you need: management: endpoints: web: exposure: include: health,info,metrics,prometheus,conditions,beans,env,loggers,threaddump,heapdump base-path: /actuator endpoint: health: show-details: when-authorized # or 'always' (dev), 'never' (public) show-components: when-authorized metrics: enabled: true server: port: 8081 # expose actuator on a separate port (not public-facing) Health Endpoint GET /actuator/health — used by Kubernetes liveness/readiness probes and load balancers:

Continue reading »

Spring Boot on Kubernetes

Kubernetes is the standard platform for running containerized microservices. Spring Boot integrates naturally with Kubernetes — Actuator probes map directly to Kubernetes probes, and Spring configuration maps to ConfigMaps and Secrets. Core Kubernetes Resources Deployment # deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: order-service labels: app: order-service spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service version: "1.2.3" spec: containers: - name: order-service image: devopsmonk/order-service:1.2.3 ports: - containerPort: 8080 name: http - containerPort: 8081 name: management # Resource limits — always set these resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "1000m" # Environment from ConfigMap and Secret envFrom: - configMapRef: name: order-service-config - secretRef: name: order-service-secrets # Individual env vars env: - name: SPRING_PROFILES_ACTIVE value: prod - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.

Continue reading »

Spring Boot Project Structure Explained

A Spring Boot project looks simple on the surface but has a specific structure with specific conventions. Understanding it upfront saves hours of confusion later. The Standard Layout order-service/ ├── pom.xml ├── mvnw # Maven Wrapper script (Unix) ├── mvnw.cmd # Maven Wrapper script (Windows) ├── .mvn/ │ └── wrapper/ │ └── maven-wrapper.properties └── src/ ├── main/ │ ├── java/ │ │ └── com/devopsmonk/orderservice/ │ │ └── OrderServiceApplication.java │ └── resources/ │ ├── application.

Continue reading »

Spring Data with PostgreSQL

PostgreSQL offers powerful features beyond basic SQL — JSONB, arrays, full-text search, advisory locks. This article shows how to use them from Spring Boot and how to tune HikariCP for production. Project Setup <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <scope>runtime</scope> </dependency> spring: datasource: url: jdbc:postgresql://localhost:5432/orderdb username: app password: ${DB_PASSWORD} driver-class-name: org.postgresql.Driver jpa: database-platform: org.hibernate.dialect.PostgreSQLDialect hibernate: ddl-auto: validate HikariCP — Connection Pool Tuning Spring Boot uses HikariCP by default — the fastest JDBC connection pool.

Continue reading »