Spring-Boot

209 posts in this section

Producing and Consuming Kafka Messages

This article implements Kafka producers and consumers with the full production setup — error handling, retries, dead-letter topics, and idempotent consumers. Producer: KafkaTemplate @Service @RequiredArgsConstructor @Slf4j public class OrderEventPublisher { private final KafkaTemplate<String, Object> kafkaTemplate; public void publishOrderCreated(Order order) { OrderCreatedEvent event = new OrderCreatedEvent( order.getId(), order.getCustomerId(), order.getCustomerEmail(), order.getItems().stream().map(OrderItemDto::from).toList(), order.getTotalAmount(), Instant.now() ); // Key = customerId: all events for same customer go to same partition kafkaTemplate.send("order-events", order.getCustomerId().toString(), event) .whenComplete((result, ex) -> { if (ex !

Continue reading »

Reading Flat Files: CSV, Fixed-Width, and Delimited with FlatFileItemReader

Introduction Flat files — CSV exports, fixed-width mainframe feeds, pipe-delimited data dumps — are the most common input source for batch jobs. Spring Batch’s FlatFileItemReader handles all of them. It is restartable out of the box: it persists its line-number position in the ExecutionContext so that a restarted job resumes exactly where it crashed. In this article you will build a complete order-import job that reads a CSV file and inserts rows into a MySQL orders table.

Continue reading »

Reading from External Sources: REST APIs, S3, and Custom ItemReaders

Introduction Not all batch input comes from files or databases. You may need to pull orders from an e-commerce API, sync products from a supplier feed, or process CSV exports stored in Amazon S3. Spring Batch provides MultiResourceItemReader for S3 files and a clean ItemReader interface for anything else. In this article you will build: A custom ItemReader that pages through a REST API An S3 reader that downloads files on demand A composite reader that merges multiple sources into one step The ItemReader Contract The entire ItemReader interface is one method:

Continue reading »

Reading from MySQL: JdbcCursorItemReader and JdbcPagingItemReader

Introduction Most real batch jobs read from a database, not a file. Spring Batch provides two JDBC readers for this: Reader Strategy Thread-safe Use when JdbcCursorItemReader Open a server-side cursor, stream rows No Single-threaded step, huge result sets JdbcPagingItemReader Execute LIMIT / OFFSET queries in a loop Yes Multi-threaded steps, sorted data Both handle restartability automatically and both work with any DataSource — including MySQL. JdbcCursorItemReader How it works The reader opens a single JDBC ResultSet on Step.

Continue reading »

Reading with JPA: JpaPagingItemReader and Entity-Based Reading

Introduction When your application already uses JPA/Hibernate, JpaPagingItemReader lets you read data using JPQL queries and mapped entities instead of raw JDBC. You get the full object graph, type-safe queries, and familiar entity lifecycle — but you also inherit JPA’s pitfalls: the N+1 problem, session-per-read overhead, and first-level cache growth. This article covers: When to choose JpaPagingItemReader over JdbcPagingItemReader Setting up the reader with JPQL and named queries Fetching associations to avoid N+1 Clearing the persistence context to prevent memory leaks A complete order-processing example with MySQL When to Use JpaPagingItemReader Use it when:

Continue reading »

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 »

Retry Logic: Handling Transient Failures Gracefully

Introduction Batch jobs interact with databases, REST APIs, and file systems — all of which fail transiently. A MySQL deadlock resolves itself in milliseconds. A network timeout to an external service clears up in seconds. Retrying these transient failures automatically is far better than failing the entire job and requiring a manual restart. Spring Batch has built-in retry support at the step level, integrated with its transaction management. This article covers everything you need to configure robust retry behaviour.

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 »