|
26 | 26 | import java.util.Optional;
|
27 | 27 | import java.util.concurrent.CompletableFuture;
|
28 | 28 | import java.util.concurrent.ConcurrentHashMap;
|
| 29 | +import java.util.concurrent.atomic.AtomicReference; |
29 | 30 | import java.util.function.Supplier;
|
30 | 31 |
|
31 | 32 | import org.apache.commons.logging.Log;
|
32 | 33 | import org.apache.commons.logging.LogFactory;
|
33 |
| -import org.reactivestreams.Subscriber; |
34 |
| -import org.reactivestreams.Subscription; |
| 34 | +import reactor.core.observability.DefaultSignalListener; |
35 | 35 | import reactor.core.publisher.Flux;
|
36 | 36 | import reactor.core.publisher.Mono;
|
37 | 37 |
|
|
90 | 90 | * @author Sam Brannen
|
91 | 91 | * @author Stephane Nicoll
|
92 | 92 | * @author Sebastien Deleuze
|
| 93 | + * @author Simon Baslé |
93 | 94 | * @since 3.1
|
94 | 95 | */
|
95 | 96 | public abstract class CacheAspectSupport extends AbstractCacheInvoker
|
@@ -1036,32 +1037,45 @@ public void performCachePut(@Nullable Object value) {
|
1036 | 1037 |
|
1037 | 1038 |
|
1038 | 1039 | /**
|
1039 |
| - * Reactive Streams Subscriber collection for collecting a List to cache. |
| 1040 | + * Reactor stateful SignalListener for collecting a List to cache. |
1040 | 1041 | */
|
1041 |
| - private class CachePutListSubscriber implements Subscriber<Object> { |
| 1042 | + private class CachePutSignalListener extends DefaultSignalListener<Object> { |
1042 | 1043 |
|
1043 |
| - private final CachePutRequest request; |
| 1044 | + private final AtomicReference<CachePutRequest> request; |
1044 | 1045 |
|
1045 | 1046 | private final List<Object> cacheValue = new ArrayList<>();
|
1046 | 1047 |
|
1047 |
| - public CachePutListSubscriber(CachePutRequest request) { |
1048 |
| - this.request = request; |
| 1048 | + public CachePutSignalListener(CachePutRequest request) { |
| 1049 | + this.request = new AtomicReference<>(request); |
1049 | 1050 | }
|
1050 | 1051 |
|
1051 | 1052 | @Override
|
1052 |
| - public void onSubscribe(Subscription s) { |
1053 |
| - s.request(Integer.MAX_VALUE); |
| 1053 | + public void doOnNext(Object o) { |
| 1054 | + this.cacheValue.add(o); |
1054 | 1055 | }
|
| 1056 | + |
1055 | 1057 | @Override
|
1056 |
| - public void onNext(Object o) { |
1057 |
| - this.cacheValue.add(o); |
| 1058 | + public void doOnComplete() { |
| 1059 | + CachePutRequest r = this.request.get(); |
| 1060 | + if (this.request.compareAndSet(r, null)) { |
| 1061 | + r.performCachePut(this.cacheValue); |
| 1062 | + } |
1058 | 1063 | }
|
| 1064 | + |
1059 | 1065 | @Override
|
1060 |
| - public void onError(Throwable t) { |
| 1066 | + public void doOnCancel() { |
| 1067 | + // Note: we don't use doFinally as we want to propagate the signal after cache put, not before |
| 1068 | + CachePutRequest r = this.request.get(); |
| 1069 | + if (this.request.compareAndSet(r, null)) { |
| 1070 | + r.performCachePut(this.cacheValue); |
| 1071 | + } |
1061 | 1072 | }
|
| 1073 | + |
1062 | 1074 | @Override
|
1063 |
| - public void onComplete() { |
1064 |
| - this.request.performCachePut(this.cacheValue); |
| 1075 | + public void doOnError(Throwable error) { |
| 1076 | + if (this.request.getAndSet(null) != null) { |
| 1077 | + this.cacheValue.clear(); |
| 1078 | + } |
1065 | 1079 | }
|
1066 | 1080 | }
|
1067 | 1081 |
|
@@ -1145,9 +1159,8 @@ public Object processPutRequest(CachePutRequest request, @Nullable Object result
|
1145 | 1159 | ReactiveAdapter adapter = (result != null ? this.registry.getAdapter(result.getClass()) : null);
|
1146 | 1160 | if (adapter != null) {
|
1147 | 1161 | if (adapter.isMultiValue()) {
|
1148 |
| - Flux<?> source = Flux.from(adapter.toPublisher(result)); |
1149 |
| - source.subscribe(new CachePutListSubscriber(request)); |
1150 |
| - return adapter.fromPublisher(source); |
| 1162 | + return adapter.fromPublisher(Flux.from(adapter.toPublisher(result)) |
| 1163 | + .tap(() -> new CachePutSignalListener(request))); |
1151 | 1164 | }
|
1152 | 1165 | else {
|
1153 | 1166 | return adapter.fromPublisher(Mono.from(adapter.toPublisher(result))
|
|
0 commit comments