Week 17 - Spring Boot 3 and Quarkus¶
Conceptual Core¶
Spring Boot is the de facto JVM web framework: vast ecosystem, opinionated defaults, deep autoconfiguration. Quarkus is the modern challenger: designed around GraalVM native-image from day one, faster cold-starts, leaner footprint. You should know both well enough to choose, and choose for reasons, not vibes.
The trade is roughly: - Spring Boot wins on ecosystem breadth, hireability, and time-to-first-working-feature for any well-known integration (databases, queues, OAuth, anything off-the-shelf). - Quarkus wins on cold start (~30ms native vs ~3s JVM), RSS (~30MB native vs ~250MB JVM), and consistency of dev-loop (live-reload built in, not retro-fitted via DevTools).
Mechanical Detail¶
- Spring Boot 3 uses Jakarta EE 9+ namespaces -
jakarta.servlet.*, notjavax.servlet.*. This break stranded every pre-2022 library that hadn't migrated; verify your transitives. - Spring autoconfiguration: starter dependencies (
spring-boot-starter-web) pull in defaults;@ConditionalOn*annotations gate beans on classpath / property / missing-bean conditions.application.ymlwith profiles (spring.profiles.active=prod). Prefer@ConfigurationProperties(typed) over@Value(untyped) for non-trivial config. Slice tests (@WebMvcTest,@DataJpaTest) load only the relevant slice - much faster than@SpringBootTest. - Spring's three controller models: blocking MVC (now on virtual threads since 3.2 with
spring.threads.virtual.enabled=true- almost always the right default for new projects), reactive WebFlux (Reactor-based; pick only if you need explicit backpressure or operator fusion over streams),RouterFunctionDSL (functional alternative to@Controller). - Quarkus: build-time DI/AOP - the design choice that makes
native-imagetractable (reflection metadata is resolved at build, not runtime).@QuarkusTest, live reload via./mvnw quarkus:dev, the extensions catalog (quarkus-jdbc-postgresql,quarkus-resteasy-reactive, ...). Native build:./mvnw package -Pnative. - Micronaut (briefly): third option, same build-time-DI philosophy as Quarkus. Smaller ecosystem; pick if you specifically need its features (compile-time AOP, GraalVM-first cloud SDK integrations).
- Honest 2026 default: Spring Boot on virtual threads for established teams; Quarkus for greenfield + serverless + native-image.
The trap
Enabling spring.threads.virtual.enabled=true while still using synchronized blocks that wrap I/O. Pre-JDK 24, that pins the virtual thread to its carrier and erases the benefit (see Week 15). Audit your dependencies - JDBC drivers were notable offenders until ~2024.
Lab¶
Build the same small REST service (book CRUD, JSON over HTTP, Postgres backend) in both Spring Boot 3 and Quarkus. Measure:
- Build time (time ./mvnw package)
- Image size (du -sh target/quarkus-app vs the Spring jar)
- Cold start (time-to-first-response after launch)
- Warm p99 latency under load (k6 or wrk, 100 RPS for 60s)
- RSS at steady state (ps -o rss -p $(pgrep -f yourapp))
Document the trade in a one-pager.
Idiomatic Drill¶
Read the autoconfiguration source for one Spring starter (spring-boot-starter-web is the canonical one). Trace how @SpringBootApplication discovers it via META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports, and how @ConditionalOnMissingBean lets your @Bean override the default.
Production Hardening Slice¶
Add Spring Boot Actuator endpoints to your template:
- /actuator/health (liveness + readiness probes)
- /actuator/metrics + /actuator/prometheus (Micrometer + Prometheus scrape)
- /actuator/info (build info - git.properties, META-INF/build-info.properties)
Quarkus equivalents: quarkus-smallrye-health, quarkus-micrometer-registry-prometheus, quarkus-info.
Lock down Actuator: expose only health and info publicly; gate metrics, env, loggers behind authentication or a private network.