From db6111fabef78b00606dd6935d8a3fe284aa84ac Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Sat, 28 Mar 2026 11:11:52 +0100 Subject: [PATCH] Add documentation notes on error handling with sync=true See gh-36531 (cherry picked from commit 529a6fc932f4a72156c676fbe24995d9dc1854e0) --- .../springframework/cache/annotation/Cacheable.java | 10 ++++++++++ .../cache/interceptor/CacheErrorHandler.java | 9 +++++++++ 2 files changed, 19 insertions(+) diff --git a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java index fa24ab07524..4f0ccd85fd6 100644 --- a/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java +++ b/spring-context/src/main/java/org/springframework/cache/annotation/Cacheable.java @@ -193,8 +193,18 @@ public @interface Cacheable { * This is effectively a hint and the chosen cache provider might not actually * support it in a synchronized fashion. Check your provider documentation for * more details on the actual semantics. + *

Note that `sync=true` leads to a combined callback operation against the + * cache provider. If this combined operation fails on initial cache access, + * there is no separate put operation to attempt anymore. Whereas for a default + * `sync=false` setup, there are independent get and put steps: If the get step + * fails but its error is suppressed in the {@code CacheErrorHandler} setup, + * there will still be a put attempt after calling the underlying method. * @since 4.3 * @see org.springframework.cache.Cache#get(Object, Callable) + * @see org.springframework.cache.Cache#get(Object) + * @see org.springframework.cache.Cache#put(Object, Object) + * @see org.springframework.cache.interceptor.CacheErrorHandler#handleCacheGetError + * @see org.springframework.cache.interceptor.CacheErrorHandler#handleCachePutError */ boolean sync() default false; diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheErrorHandler.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheErrorHandler.java index a9d027b0235..b1ee6bda205 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheErrorHandler.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheErrorHandler.java @@ -16,6 +16,8 @@ package org.springframework.cache.interceptor; +import java.util.concurrent.Callable; + import org.springframework.cache.Cache; import org.springframework.lang.Nullable; @@ -38,10 +40,17 @@ public interface CacheErrorHandler { * Handle the given runtime exception thrown by the cache provider when * retrieving an item with the specified {@code key}, possibly * rethrowing it as a fatal exception. + *

Note that for a default {@code @Cacheable} setup, this will be called + * after an initial cache access failure, whereas the subsequent put step may + * independently fail and be handled in {@link #handleCachePutError} still. + * However, for {@code @Cacheable(sync=true)}, there is only a combined get step + * with {@code handleCacheGetError} being called in case of failure; there won't + * be a separate put attempt after initial cache access failure anymore. * @param exception the exception thrown by the cache provider * @param cache the cache * @param key the key used to get the item * @see Cache#get(Object) + * @see Cache#get(Object, Callable) */ void handleCacheGetError(RuntimeException exception, Cache cache, Object key);