Spring logo

Languages & Frameworks

Official site

Spring

Spring — the dominant Java application framework, productive by default and full of defaults worth checking.

Overview

Spring and Spring Boot appear across my Java work, most fully in a RabbitMQ tutorial built on Java 25 and Spring Boot 4.2.0-RC1 with Spring AMQP. Every claim there about how the broker or Spring behaves is a test against a real broker.

Messaging is where Spring's abstractions hide the most. RabbitTemplate and @RabbitListener make a hello-world easy, but acknowledgements, prefetch, publisher confirms, retries and dead-letter queues decide what happens to a message in production.

Transactions have their own traps. Spring's documented default is that a checked exception does not roll back a transactional method, and hiding the exception from the compiler with Lombok's @SneakyThrows changes nothing: in my test against a real database, the row was still committed.

Callbacks can mislead as well. isActualTransactionActive() stays true during after-commit callbacks, when the work has already been committed, so a check that looks correct can pass while the data is lost.

Dependency injection is simple until generated code joins in. A @Qualifier on a Lombok field stays on the field and does not reach the generated constructor parameter, which is the one Spring reads.

Module boundaries can be tested. In my article on architecture decision records I use ArchUnit on a modular-monolith shop and point to Spring Modulith as the equivalent on Spring.

How I Work With Spring

I read the default before relying on it. Rollback rules, acknowledgement modes and retry behaviour are all defaults that shape what happens during a failure.

I test framework behaviour against the real dependency. A messaging claim gets a real broker, because a mock cannot show what the broker does with the message.

I decide what happens to a failed message on purpose. A retry needs a limit, and the message needs somewhere to go once that limit is reached.

I use constructor injection, and I check how generated constructors carry annotations before relying on them.

I treat a transaction boundary as a design decision. I check which exceptions roll it back and whether code running in a callback can still commit anything.

I state the exact Spring version with every claim, especially on a release candidate, so a reader can tell whether it still holds.

Key Capabilities

A Spring Boot 4.2 application with Spring AMQP, tested against a real RabbitMQ broker.
Acknowledgements, prefetch, publisher confirms, retries and dead-letter queues.
Transaction behaviour: rollback rules, proxies and after-commit callbacks.
Constructor injection and how Lombok-generated code interacts with it.
Module boundaries enforced by tests.