What ACLs Solve Role-based access control answers: “Can this user perform this action?” ACLs answer: “Can this user perform this action on this specific object?” Consider a document management system: Alice owns Document #42 — she can read and edit it Bob is a reviewer on Document #42 — he can read it but not edit Carol has no permission on Document #42 — she gets a 403 This cannot be expressed with roles alone.
Continue reading »Spring-Boot
209 posts in this section
Dynamic Listener Containers and Programmatic Topic Registration
Why Dynamic Listeners? @KafkaListener is declared at compile time. Some scenarios require listeners created at runtime: Multi-tenant SaaS — each tenant onboards to their own topic; you can’t redeploy to add @KafkaListener for each new tenant Feature flags — enable or disable a listener without a deployment Plugin systems — modules register their own topic subscriptions when loaded Admin APIs — operators subscribe to new topics via a REST endpoint ConcurrentMessageListenerContainer The core building block is ConcurrentMessageListenerContainer — the same class @KafkaListener uses internally, but constructed and started manually:
Continue reading »Embedded Types and Value Objects: @Embeddable and @Embedded
Introduction Not every concept in your domain deserves its own table. An Address — street, city, state, postal code — is a value object: it has no identity of its own, it belongs to an entity. JPA’s @Embeddable lets you model this as a separate Java class while storing it in the owning entity’s table. What Is an Embeddable? An @Embeddable class is a Java class whose fields are mapped to columns in the owning entity’s table — not a separate table.
Continue reading »Entity Graphs and Batch Loading: Precision Fetching
The Problem @EntityGraph Solves JOIN FETCH in @Query solves N+1 but creates inflexibility: the fetch plan is baked into the query. Two different use cases — an order detail page (needs items + customer) and an order list page (needs only customer) — require two different queries with different JOIN FETCHes. @EntityGraph separates the fetch plan from the query. You define what to load at the call site, and Spring Data JPA generates the appropriate JOIN.
Continue reading »Entity Lifecycle States: Transient, Managed, Detached, Removed
Introduction Every JPA entity is always in one of four states. The state determines whether Hibernate is tracking the entity, whether changes are detected automatically, and what operations are valid. Understanding these states explains a large class of JPA bugs — especially the dreaded LazyInitializationException and detached entity errors. The Four States new Customer() │ │ persist / save() ▼ TRANSIENT ──────────────────────► MANAGED (not tracked) (tracked by persistence context) │ │ evict / clear / close ▼ DETACHED (no longer tracked) │ │ merge() ▼ MANAGED (re-attached) MANAGED ─── remove / delete() ──► REMOVED (delete scheduled, still in context) 1.
Continue reading »Error Handling Basics: DefaultErrorHandler and CommonErrorHandler
What Happens When a Listener Throws? Without an error handler, an uncaught exception from @KafkaListener causes the container to log the error and retry the same record on the next poll — indefinitely. One bad record can block an entire partition forever. DefaultErrorHandler fixes this: it retries a configurable number of times with backoff, then calls a ConsumerRecordRecoverer (e.g. send to a dead-letter topic) and moves on. DefaultErrorHandler — The Modern API Spring Kafka 2.
Continue reading »Fetch Types: EAGER vs LAZY Loading
Introduction Every relationship in JPA has a fetch type: either EAGER (load immediately with the parent) or LAZY (load only when accessed). The defaults are counterintuitive, and getting fetch types wrong is one of the top causes of performance problems and LazyInitializationException in JPA applications. Default Fetch Types Annotation Default fetch type Performance risk @ManyToOne EAGER Loads related entity on every query — can be expensive @OneToOne EAGER Same — loads profile/address on every customer load @OneToMany LAZY Correct default — collections are only loaded when needed @ManyToMany LAZY Correct default The defaults for @ManyToOne and @OneToOne are EAGER — a poor choice that the JPA spec made for historical reasons.
Continue reading »Filtering Messages with RecordFilterStrategy
Why Filter at the Container Level? Multiple consumers can share a topic. The inventory service only cares about PLACED orders; the analytics service wants everything. Rather than putting if (event.getStatus() != PLACED) return; at the top of every listener, Spring Kafka lets you filter records before they reach your method — keeping business logic clean and making the filter reusable across listeners. How RecordFilterStrategy Works flowchart LR Broker -->|"poll() → [r1, r2, r3, r4]"
Continue reading »Form Login Authentication: From Request to Session
Form Login: The Classic Web Authentication Flow Form login is the traditional authentication mechanism for server-rendered web applications. The user fills in a username and password form, the server verifies credentials, creates a session, and returns a session cookie. All subsequent requests carry that cookie. sequenceDiagram participant Browser participant SSF as Spring Security Filters participant AM as AuthenticationManager participant SS as HTTP Session Store participant Controller Browser->>SSF: GET /dashboard (unauthenticated) SSF->>SS: Save original request (RequestCache) SSF-->>Browser: 302 Redirect to /login Browser->>SSF: GET /login SSF-->>Browser: 200 HTML login page Browser->>SSF: POST /login {username, password} SSF->>AM: authenticate(UsernamePasswordToken) AM-->>SSF: Authentication (success) SSF->>SS: Store SecurityContext in session SSF-->>Browser: 302 Redirect to /dashboard\nSet-Cookie: JSESSIONID=abc123 Browser->>SSF: GET /dashboard (JSESSIONID cookie) SSF->>SS: Load SecurityContext from session SSF->>Controller: Request with authenticated user Controller-->>Browser: 200 Dashboard HTML Minimal Configuration @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .
Continue reading »Handling Deserialization Errors Gracefully
The Problem: Poison Pills at Deserialization Time A malformed byte sequence — truncated JSON, wrong Avro schema, corrupt payload — throws an exception during deserialization, before the listener method is called. Without special handling, this record blocks the partition indefinitely: the consumer fetches it, fails to deserialize, and fetches it again on the next poll. sequenceDiagram participant Broker participant Container participant Deserializer loop forever without ErrorHandlingDeserializer Container->>Broker: poll() Broker-->>Container: [good-record, CORRUPT-RECORD, good-record] Container->>Deserializer: deserialize(CORRUPT-RECORD) Deserializer-->>Container: JsonProcessingException 💥 Note over Container: Partition blocked — same record on every poll end ErrorHandlingDeserializer solves this by catching the deserialization exception and wrapping it in a DeserializationException that the listener container can route to the error handler.
Continue reading »