mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-23 22:59:03 +00:00
Merge branch '7.0.x'
This commit is contained in:
@@ -216,8 +216,8 @@ documentation of your cache provider for more details.
|
||||
[[cache-annotations-cacheable-reactive]]
|
||||
=== Caching with CompletableFuture and Reactive Return Types
|
||||
|
||||
As of 6.1, cache annotations take `CompletableFuture` and reactive return types
|
||||
into account, automatically adapting the cache interaction accordingly.
|
||||
Cache annotations take `CompletableFuture` and reactive return types into account,
|
||||
automatically adapting the cache interaction accordingly.
|
||||
|
||||
For a method returning a `CompletableFuture`, the object produced by that future
|
||||
will be cached whenever it is complete, and the cache lookup for a cache hit will
|
||||
@@ -250,6 +250,10 @@ and the cache lookup for a cache hit will be retrieved as a `Flux` (backed by a
|
||||
public Flux<Book> findBooks(String author) {...}
|
||||
----
|
||||
|
||||
This collected `List` is also what an `unless` SpEL expression sees as the `#result` for
|
||||
such a method (see <<cache-spel-context,SpEL evaluation context>>); the `Flux` returned
|
||||
to the caller is unaffected by this collection process.
|
||||
|
||||
Such `CompletableFuture` and reactive adaptation also works for synchronized caching,
|
||||
computing the value only once in case of a concurrent cache miss:
|
||||
|
||||
@@ -381,10 +385,12 @@ available to the context so that you can use them for key and conditional comput
|
||||
|
||||
| `result`
|
||||
| Evaluation context
|
||||
| The result of the method call (the value to be cached). Only available in `unless`
|
||||
expressions, `cache put` expressions (to compute the `key`), or `cache evict`
|
||||
expressions (when `beforeInvocation` is `false`). For supported wrappers (such as
|
||||
`Optional`), `#result` refers to the actual object, not the wrapper.
|
||||
| The result of the method call (the value to be cached, or evaluated for eviction). Only
|
||||
available in `unless` expressions, `cache put` expressions (`key`, `condition`, or
|
||||
`unless`), or `cache evict` expressions (`key` or `condition`, when `beforeInvocation`
|
||||
is `false`). For supported wrappers (such as `Optional`), `#result` refers to the
|
||||
actual object, not the wrapper. For a method returning a `Flux`, `#result` refers to a
|
||||
`List` containing all values collected from the `Flux`.
|
||||
| `#result`
|
||||
|===
|
||||
|
||||
@@ -413,8 +419,8 @@ other), such declarations should be avoided. Note also that such conditions shou
|
||||
on the result object (that is, the `#result` variable), as these are validated up-front to
|
||||
confirm the exclusion.
|
||||
|
||||
As of 6.1, `@CachePut` takes `CompletableFuture` and reactive return types into account,
|
||||
performing the put operation whenever the produced object is available.
|
||||
`@CachePut` takes `CompletableFuture` and reactive return types into account, performing
|
||||
the put operation whenever the produced object is available.
|
||||
|
||||
TIP: When `@CachePut` is combined with `@Retryable`, the retry advice is applied
|
||||
outermost, so each successful retry attempt updates the cache; a failed attempt does
|
||||
@@ -463,8 +469,13 @@ trigger, the return values are ignored (as they do not interact with the cache).
|
||||
not the case with `@Cacheable` which adds data to the cache or updates data in the cache
|
||||
and, thus, requires a result.
|
||||
|
||||
As of 6.1, `@CacheEvict` takes `CompletableFuture` and reactive return types into account,
|
||||
performing an after-invocation evict operation whenever processing has completed.
|
||||
`@CacheEvict` takes `CompletableFuture` and reactive return types into account,
|
||||
performing an after-invocation evict operation whenever processing has completed. As with
|
||||
`@Cacheable` and `@CachePut`, for a method returning a `Flux`, all emitted elements are
|
||||
collected into a `List` before the evict operation is performed. When `beforeInvocation`
|
||||
is `false`, that same `List` is what the `condition` SpEL expression sees as the
|
||||
`#result`. Either way, the `Flux` returned to the caller is unaffected by this collection
|
||||
process.
|
||||
|
||||
TIP: When `@CacheEvict` is combined with `@Retryable`, the retry advice is applied
|
||||
outermost, so eviction runs again on every retry attempt -- and, with
|
||||
|
||||
+14
-8
@@ -28,7 +28,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) triggers a
|
||||
* {@link org.springframework.cache.Cache#evict(Object) cache evict} operation.
|
||||
* {@linkplain org.springframework.cache.Cache#evict(Object) cache evict} operation.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em> with attribute overrides.
|
||||
@@ -77,14 +77,15 @@ public @interface CacheEvict {
|
||||
* <li>{@code #result} for a reference to the result of the method invocation, which
|
||||
* can only be used if {@link #beforeInvocation()} is {@code false}. For supported
|
||||
* wrappers such as {@code Optional}, {@code #result} refers to the actual object,
|
||||
* not the wrapper</li>
|
||||
* not the wrapper. For a method that returns a {@code Flux}, {@code #result} refers
|
||||
* to a {@code List} containing all values collected from the {@code Flux}.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -117,19 +118,24 @@ public @interface CacheEvict {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* eviction operation conditional. Evict that cache if the condition evaluates
|
||||
* to {@code true}.
|
||||
* eviction operation conditional. Evicts from the cache if the condition
|
||||
* evaluates to {@code true}.
|
||||
* <p>Default is {@code ""}, meaning the cache eviction is always performed.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation, which
|
||||
* can only be used if {@link #beforeInvocation()} is {@code false}. For supported
|
||||
* wrappers such as {@code Optional}, {@code #result} refers to the actual object,
|
||||
* not the wrapper. For a method that returns a {@code Flux}, {@code #result} refers
|
||||
* to a {@code List} containing all values collected from the {@code Flux}.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
|
||||
+20
-14
@@ -28,14 +28,14 @@ import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Annotation indicating that a method (or all methods on a class) triggers a
|
||||
* {@link org.springframework.cache.Cache#put(Object, Object) cache put} operation.
|
||||
* {@linkplain org.springframework.cache.Cache#put(Object, Object) cache put} operation.
|
||||
*
|
||||
* <p>In contrast to the {@link Cacheable @Cacheable} annotation, this annotation
|
||||
* does not cause the advised method to be skipped. Rather, it always causes the
|
||||
* method to be invoked and its result to be stored in the associated cache if the
|
||||
* {@link #condition()} and {@link #unless()} expressions match accordingly. Note
|
||||
* that Java8's {@code Optional} return types are automatically handled and its
|
||||
* content is stored in the cache if present.
|
||||
* that Java's {@code Optional} return types are automatically handled and their
|
||||
* contents are stored in the cache if present.
|
||||
*
|
||||
* <p>This annotation may be used as a <em>meta-annotation</em> to create custom
|
||||
* <em>composed annotations</em> with attribute overrides.
|
||||
@@ -84,14 +84,16 @@ public @interface CachePut {
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
|
||||
* refers to a {@code List} containing all values collected from the {@code Flux},
|
||||
* mirroring the value that is cached.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -124,7 +126,7 @@ public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the cache
|
||||
* put operation conditional. Update the cache if the condition evaluates to
|
||||
* put operation conditional. Updates the cache if the condition evaluates to
|
||||
* {@code true}.
|
||||
* <p>This expression is evaluated after the method has been called due to the
|
||||
* nature of the put operation and can therefore refer to the {@code result}.
|
||||
@@ -134,14 +136,16 @@ public @interface CachePut {
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
|
||||
* refers to a {@code List} containing all values collected from the {@code Flux},
|
||||
* mirroring the value that is cached.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -149,21 +153,23 @@ public @interface CachePut {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used to veto the cache put operation.
|
||||
* Veto updating the cache if the condition evaluates to {@code true}.
|
||||
* Vetoes updating the cache if the condition evaluates to {@code true}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
* following meta-data:
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
|
||||
* refers to a {@code List} containing all values collected from the {@code Flux},
|
||||
* mirroring the value that is cached.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
* @since 3.2
|
||||
|
||||
+11
-9
@@ -104,8 +104,8 @@ public @interface Cacheable {
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -138,7 +138,7 @@ public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used for making the method
|
||||
* caching conditional. Cache the result if the condition evaluates to
|
||||
* caching conditional. Caches the result if the condition evaluates to
|
||||
* {@code true}.
|
||||
* <p>Default is {@code ""}, meaning the method result is always cached.
|
||||
* <p>The SpEL expression evaluates against a dedicated context that provides the
|
||||
@@ -149,8 +149,8 @@ public @interface Cacheable {
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
*/
|
||||
@@ -158,7 +158,7 @@ public @interface Cacheable {
|
||||
|
||||
/**
|
||||
* Spring Expression Language (SpEL) expression used to veto method caching.
|
||||
* Veto caching the result if the condition evaluates to {@code true}.
|
||||
* Vetoes caching of the result if the condition evaluates to {@code true}.
|
||||
* <p>Unlike {@link #condition}, this expression is evaluated after the method
|
||||
* has been called and can therefore refer to the {@code result}.
|
||||
* <p>Default is {@code ""}, meaning that caching is never vetoed.
|
||||
@@ -167,14 +167,16 @@ public @interface Cacheable {
|
||||
* <ul>
|
||||
* <li>{@code #result} for a reference to the result of the method invocation. For
|
||||
* supported wrappers such as {@code Optional}, {@code #result} refers to the actual
|
||||
* object, not the wrapper</li>
|
||||
* object, not the wrapper. For a method that returns a {@code Flux}, {@code #result}
|
||||
* refers to a {@code List} containing all values collected from the {@code Flux},
|
||||
* mirroring the value that would be cached.</li>
|
||||
* <li>{@code #root.method}, {@code #root.target}, and {@code #root.caches} for
|
||||
* references to the {@link java.lang.reflect.Method method}, target object, and
|
||||
* affected cache(s) respectively.</li>
|
||||
* <li>Shortcuts for the method name ({@code #root.methodName}) and target class
|
||||
* ({@code #root.targetClass}) are also available.
|
||||
* <li>Method arguments can be accessed by index. For instance the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1} or {@code #a1}. Arguments
|
||||
* <li>Method arguments can be accessed by index. For example, the second argument
|
||||
* can be accessed via {@code #root.args[1]}, {@code #p1}, or {@code #a1}. Arguments
|
||||
* can also be accessed by name if that information is available.</li>
|
||||
* </ul>
|
||||
* @since 3.2
|
||||
|
||||
+43
-2
@@ -1088,6 +1088,39 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reactive Streams Subscriber for exhausting the Flux and collecting a List
|
||||
* to evaluate for eviction.
|
||||
*/
|
||||
private final class CacheEvictListSubscriber implements Subscriber<Object> {
|
||||
|
||||
private final List<CacheOperationContext> contexts;
|
||||
|
||||
private final List<Object> cacheValue = new ArrayList<>();
|
||||
|
||||
public CacheEvictListSubscriber(List<CacheOperationContext> contexts) {
|
||||
this.contexts = contexts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubscribe(Subscription s) {
|
||||
s.request(Integer.MAX_VALUE);
|
||||
}
|
||||
@Override
|
||||
public void onNext(Object o) {
|
||||
this.cacheValue.add(o);
|
||||
}
|
||||
@Override
|
||||
public void onError(Throwable t) {
|
||||
this.cacheValue.clear();
|
||||
}
|
||||
@Override
|
||||
public void onComplete() {
|
||||
performCacheEvicts(this.contexts, this.cacheValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid a hard dependency on the Reactive Streams API at runtime.
|
||||
*/
|
||||
@@ -1169,8 +1202,16 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
||||
public @Nullable Object processCacheEvicts(List<CacheOperationContext> contexts, @Nullable Object result) {
|
||||
ReactiveAdapter adapter = (result != null ? this.registry.getAdapter(result.getClass()) : null);
|
||||
if (adapter != null) {
|
||||
return adapter.fromPublisher(Mono.from(adapter.toPublisher(result))
|
||||
.doOnSuccess(value -> performCacheEvicts(contexts, value)));
|
||||
if (adapter.isMultiValue()) {
|
||||
Flux<?> source = Flux.from(adapter.toPublisher(result))
|
||||
.publish().refCount(2);
|
||||
source.subscribe(new CacheEvictListSubscriber(contexts));
|
||||
return adapter.fromPublisher(source);
|
||||
}
|
||||
else {
|
||||
return adapter.fromPublisher(Mono.from(adapter.toPublisher(result))
|
||||
.doOnSuccess(value -> performCacheEvicts(contexts, value)));
|
||||
}
|
||||
}
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
|
||||
+4
-3
@@ -56,6 +56,7 @@ import static org.mockito.Mockito.verify;
|
||||
* @author Phillip Webb
|
||||
* @author Juergen Hoeller
|
||||
* @author Stephane Nicoll
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
class CacheReproTests {
|
||||
|
||||
@@ -312,7 +313,7 @@ class CacheReproTests {
|
||||
assertThat(bean.findById("tb1").collectList().block()).isEqualTo(tb);
|
||||
assertThat(cache.get("tb1").get()).isEqualTo(tb);
|
||||
|
||||
bean.clear().blockLast();
|
||||
assertThat(bean.clear().collectList().block()).containsExactly(1, 2, 3);
|
||||
List<TestBean> tb2 = bean.findById("tb1").collectList().block();
|
||||
assertThat(tb2).isNotEmpty();
|
||||
assertThat(tb2).isNotEqualTo(tb);
|
||||
@@ -705,9 +706,9 @@ class CacheReproTests {
|
||||
return Flux.fromIterable(item);
|
||||
}
|
||||
|
||||
@CacheEvict(cacheNames = "itemCache", allEntries = true, condition = "#result > 0")
|
||||
@CacheEvict(cacheNames = "itemCache", allEntries = true, condition = "#result == {1, 2, 3}")
|
||||
public Flux<Integer> clear() {
|
||||
return Flux.just(1);
|
||||
return Flux.just(1, 2, 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user