rgoussu@goussu: ~/library/java/frameworks
~/library/java/frameworks cat spring.md

Spring deep dive

# The Spring stack in depth — IoC container, AOP proxies, Boot auto-configuration, MVC vs WebFlux, Data, Security, transactions and testing.

Conceptsaved 2026-08-09 #java#frameworks#spring#spring-boot#aop#testing

Overview

Spring is less a framework than an ecosystem: an IoC container (spring-core, spring-context) with everything else — web, data, security, messaging, batch — layered on top and wired by Spring Boot's auto-configuration. Its power is the integration surface: whatever you need to talk to, there is a starter for it. Its costs are runtime reflection, proxy-based AOP with real gotchas, and a footprint the build-time frameworks were invented to undercut — which Boot 3.x answers with GraalVM AOT and virtual-thread support.

Key points

  • IoC container: beans defined via @Configuration + @Bean methods or component scanning (@Component, @Service, @Repository); singleton scope by default; lifecycle callbacks (@PostConstruct, @PreDestroy, BeanPostProcessor).
  • AOP by proxy: @Transactional, @Cacheable, @Async work through JDK dynamic proxies or CGLIB subclasses — hence the self-invocation gotcha (calls within the same bean bypass the proxy and the advice silently never runs).
  • Spring Boot: opinionated auto-configuration driven by classpath presence and @ConditionalOn* conditions; starters (spring-boot-starter-web, -data-jpa, -security); Actuator for health/metrics; externalized config with profiles and relaxed binding.
  • Two web stacks: Spring MVC (servlet, blocking, spring-webmvc on Tomcat/Jetty) vs WebFlux (reactive, spring-webflux on Reactor/Netty) — don't mix casually.
  • Spring Data: repository interfaces with derived queries; Spring Security: an ordered servlet filter chain; declarative transactions via @Transactional.
  • Boot 3.x baseline: Java 17+, jakarta.* namespace (Jakarta EE 10), AOT engine for GraalVM native image, spring.threads.virtual.enabled=true for Loom.
  • Standards stance: Spring implements few Jakarta specs itself but consumes them — JPA via Hibernate, the Servlet API, Bean Validation via Hibernate Validator.

Details

Container and configuration

The ApplicationContext builds a bean graph at startup: component scanning finds annotated classes, @Configuration classes contribute @Bean factory methods, and dependency injection is by constructor (preferred), setter, or field. Startup cost is proportional to scanning and reflection — the exact work Quarkus/Micronaut shift to build time. @Profile and @Conditional gate beans per environment.

AOP and its gotchas

Spring AOP is proxy-based, not bytecode weaving (that would be AspectJ). Consequences worth internalizing: only public external calls are advised; self-invocation (this. transactionalMethod()) skips the proxy — the classic "why didn't my transaction roll back" bug; CGLIB proxies require a non-final class and no-arg constructible hierarchy.

Transactions

@Transactional semantics: propagation (REQUIRED default, REQUIRES_NEW suspends), isolation, readOnly as a hint, and rollback rules — unchecked exceptions roll back by default, checked ones do not unless rollbackFor says so. Under the hood it is an interceptor binding a JDBC/JPA transaction to the thread — which is exactly why it interacts carefully with virtual threads and not at all with code that hops threads.

Web, data, security

  • MVC: @RestController, @RequestMapping, message conversion via Jackson; RestClient (sync) and WebClient (reactive) as HTTP clients.
  • WebFlux: Mono/Flux from Project Reactor end-to-end; worth it only when the whole call chain (including the driver — R2DBC, reactive Mongo) is non-blocking. Virtual threads erode much of its motivation for plain request/response services.
  • Spring Data: JpaRepository<User, Long> with derived queries (findByEmailAndActiveTrue), @Query for the rest; sibling modules for Mongo, Redis, Elasticsearch keep the same programming model.
  • Spring Security: a SecurityFilterChain bean of ordered filters (authentication → authorization); first-class OAuth2/OIDC client and resource-server support (spring-boot-starter-oauth2-resource-server).

Testing

Test slices load partial contexts: @WebMvcTest (controllers + MockMvc), @DataJpaTest (repositories + embedded/Testcontainers DB), @JsonTest. Full-context @SpringBootTest is the integration hammer — slow, so cache-friendly test design (consistent context configuration) matters. @MockitoBean (formerly @MockBean) replaces beans with mocks; @ServiceConnection wires Testcontainers straight into config.

Examples

@Service
public class OrderService {
  private final OrderRepository repo;
  OrderService(OrderRepository repo) { this.repo = repo; }   // constructor injection

  @Transactional
  public Order place(OrderRequest req) { ... }

  public void batch(List<OrderRequest> reqs) {
    reqs.forEach(this::place);   // BUG: self-invocation — @Transactional not applied
  }
}

Related