Spring-core 7 Does Not Support ExceptionCauseClassifierRetryPolicy
Summary
Spring Core 7 has deprecated ExceptionCauseClassifierRetryPolicy and introduced a new retry configuration paradigm using RetryPolicy with policy lambdas. Legacy customization via PolicyMap integration is no longer supported, forcing developers to rearchitect retry strategies.
Root Cause
The ExceptionCauseClassifierRetryPolicy was removed due to design simplification and better type safety. Key changes:
- Policy registration and classification workflows were streamlined.
SimpleRetryPolicyandAlwaysRetryPolicybecame standalone policy builders.- Retry behavior is now driven by
<P extends Throwable, R extends Policy> PolicyBuilder<P, R>interfaces.
Why This Happens in Real Systems
- Deprecation of key classes:
ExceptionCauseClassifierRetryPolicywas replaced with simpler policy objects. - Lambda-based policies: Developers now define retry logic via lambda expressions instead of custom
RetryPolicyinstances.// Old (Spring 6) policyMap.put(SQLException.class, retryWithMaxAttempts);
// New (Spring 7)
.retryPolicy(
(P) -> { / exception parameters / },
(p) -> {
if (p instanceof SQLException) { // Not valid due to type erasure issues
return retryWithMaxAttempts;
}
return connectionRetryPolicy;
}
);
- **Type erasure pitfalls**: Retry policies now rely on parameterized lambdas, complicating exception type handling.
## Real-World Impact
- **Increased complexity** in configuring conditional retries.
- **Runtime `ClassCastException`** when mismatched exception types are detected due to type erasure.
- **Configuration drift** if migration scripts aren’t updated for new syntax.
## Example or Code
```java
// New Spring 7 configuration
Retrier retrier = Retriers.retryWhen(
(metadata, context, throwable) -> {
if (throwable instanceof SQLException) {
return RetryPolicy.withMaxAttempts(3);
} else if (throwable instanceof SocketException) {
return RetryPolicy.NEVER;
}
throw throwable;
}
);
How Senior Engineers Fix It
- Refactor retry logic using the new policy builder APIs:
CorrelationContext.correlate(requestId, correlation -> { CorrelationScope correlationScope = CorrelationScope.of(correlation); return Retriers.retryWhen( correlationScope, // Inherit correlation headers e -> { if (e instanceof SQLException) { return RetryPolicy.withBackoff(500, RetryAlgorithmOptions.forExponentialBackoff()); } return RetryPolicy.NEVER; } ) .run(() -> api.makeRequest()); });
Why Juniors Miss It
Juniors miss this because:
- Incomplete migration guides: Team documentation might not reflect removal flags.
- Legacy examples: Copying old snippets without updating for new policy builders.
- Overemphasizing initialization: Focusing on retrier instantiation rather than policy lambda semantics.
- Developer errors: Hardcoding exception class checks in lambdas without considering type erasure.
Key Takeaways:
ExceptionCauseClassifierRetryPolicyis gone.- Policies are defined via lambdas, not a
PolicyMap. - Test retry logic with
@Retryablefallback using exception hierarchies. - Use Spring Retry’s
is()andretry()helpers to simplify conditional logic.