# 1. Two resilience stacks on one classpath [README](../README.md) | Next: [02-circuit-breaker.md](02-circuit-breaker.md) Spring Boot 4.1 sits on Spring Framework 7, and Framework 7 shipped something new under `org.springframework.resilience`: `@Retryable`, `@ConcurrencyLimit`, and the annotation that turns them on, `@EnableResilientMethods`. None of this existed in Framework 6. This repo pins down exactly what moved into core, what didn't, and two build breaks you will hit the moment you try to wire it up on Boot 4 — both found by running the build, not by reading a changelog. ## What's actually in core (verified by `javap`, not by the reference docs) `org.springframework.resilience.annotation.Retryable` (an annotation, not the unrelated `org.springframework.core.retry.Retryable` *interface* that also ships in `spring-core` — two classes with the same simple name in the same major version, easy to import the wrong one): ``` value(), includes(), excludes(), predicate(), maxRetries(), maxRetriesString(), timeout(), timeoutString(), delay(), delayString(), jitter(), jitterString(), multiplier(), multiplierString(), maxDelay(), maxDelayString(), timeUnit() ``` `org.springframework.resilience.annotation.ConcurrencyLimit`: ``` value(), limit(), limitString(), policy() // policy: BLOCK (default) or REJECT ``` Neither annotation has a `fallbackMethod` attribute. Retrying exhausted just rethrows. Rejecting under `REJECT` throws `org.springframework.resilience.InvocationRejectedException` (a `java.util.concurrent.RejectedExecutionException` subtype) straight at the caller. There is no circuit breaker class anywhere in `spring-context-7.0.9.jar` (grepped the whole jar listing for `circuitbreaker`, `ratelimit`, `bulkhead` — zero matches). `@ConcurrencyLimit` is the closest core has to a Resilience4j Bulkhead, and even that is a decades-old class repurposed: `ConcurrencyLimitBeanPostProcessor$ResilienceConcurrencyThrottleInterceptor` extends `org.springframework.aop.interceptor.ConcurrencyThrottleInterceptor`, which has shipped in Spring since the 1.x era. ## `@EnableResilientMethods` is not automatic Spring Boot 4.1's autoconfigure jar carries no auto-configuration for the resilience package — grepping `spring-boot-autoconfigure-4.1.1.jar`'s listing for "resilien" returns nothing. You must put `@EnableResilientMethods` on a `@Configuration` class yourself (this repo puts it on the `@SpringBootApplication` class). Skip it and the annotations are inert: no error, no log line, the method just runs unprotected. ## Build break #1: `spring-boot-starter-aop` no longer exists Every pre-Boot-4 Resilience4j guide, including the version of this post it replaces, tells you to add `spring-boot-starter-aop`. On Boot 4 that dependency breaks the build outright: ``` [ERROR] 'dependencies.dependency.version' for org.springframework.boot:spring-boot-starter-aop:jar is missing. ``` `repo1.maven.org/maven2/org/springframework/boot/spring-boot-starter-aop/maven-metadata.xml` confirms it: the last version ever published is `4.0.0-M2`, a milestone. It never reached Boot 4.0 GA and was not revived for 4.1. The fix is `org.springframework:spring-aop` directly — see [pom.xml](../pom.xml). ## Build break #2 (silent): no `aspectjweaver`, no proxy, no error Swapping in `spring-aop` alone gets you a clean build and a **wrong result**. Resilience4j's Spring integration (`resilience4j-spring6`, which is what `resilience4j-spring-boot4` actually depends on — see below) implements `CircuitBreakerAspect`, `BulkheadAspect`, `RateLimiterAspect` and friends as real `@Aspect` classes (confirmed with `unzip -l` on the jar). Spring's `AnnotationAwareAspectJAutoProxyCreator` needs `org.aspectj:aspectjweaver` on the classpath to even recognise a bean as an aspect. Without it, **zero proxies get created, for anything** — Resilience4j's annotations and Spring's own `@Retryable` both go completely inert, silently. That is exactly what happened building this repo: `CircuitBreakerTripAndRecoverTest` failed with the raw `DownstreamUnavailableException` propagating straight out of `R4jPaymentService`, no fallback, no state tracking — because there was no proxy in front of it at all. Adding `org.aspectj:aspectjweaver` fixed every failing test in the same run. `spring-boot-starter-aop` used to bundle this for you; its replacement doesn't, and nothing tells you that. ## A naming trap in the dependency itself `resilience4j-spring-boot4` is a real, separate artifact from `resilience4j-spring-boot3` (both currently at `2.4.0`) — but its own POM depends on `resilience4j-spring6`, `spring-core 7.0.2`, `spring-context 7.0.2` and `spring-boot-autoconfigure 4.0.0`. The "spring-boot4" in the artifact name is about which *Boot* generation it targets, not which internal Resilience4j module version it's built on — that module never got renamed to "spring7". If you're grepping your dependency tree for "spring7" expecting to find the pieces Boot 4.1 pulls in, you won't. Next: [02-circuit-breaker.md](02-circuit-breaker.md) — the Resilience4j side, verified against a real trip/recover run.