Browse Source

Polishing

pull/31496/head
Juergen Hoeller 2 years ago
parent
commit
4ce1ac0dcb
  1. 8
      spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java
  2. 28
      spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java
  3. 14
      spring-context/src/main/java/org/springframework/cache/Cache.java
  4. 8
      spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java
  5. 22
      spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java
  6. 8
      spring-context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java
  7. 4
      spring-context/src/test/java/org/springframework/cache/CacheReproTests.java

8
spring-context-support/src/main/java/org/springframework/cache/caffeine/CaffeineCacheManager.java vendored

@ -110,7 +110,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the Caffeine to use for building each individual * Set the Caffeine to use for building each individual
* {@link CaffeineCache} instance. * {@link CaffeineCache} instance.
* @see #createNativeCaffeineCache * @see #createNativeCaffeineCache
* @see com.github.benmanes.caffeine.cache.Caffeine#build() * @see Caffeine#build()
*/ */
public void setCaffeine(Caffeine<Object, Object> caffeine) { public void setCaffeine(Caffeine<Object, Object> caffeine) {
Assert.notNull(caffeine, "Caffeine must not be null"); Assert.notNull(caffeine, "Caffeine must not be null");
@ -121,7 +121,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the {@link CaffeineSpec} to use for building each individual * Set the {@link CaffeineSpec} to use for building each individual
* {@link CaffeineCache} instance. * {@link CaffeineCache} instance.
* @see #createNativeCaffeineCache * @see #createNativeCaffeineCache
* @see com.github.benmanes.caffeine.cache.Caffeine#from(CaffeineSpec) * @see Caffeine#from(CaffeineSpec)
*/ */
public void setCaffeineSpec(CaffeineSpec caffeineSpec) { public void setCaffeineSpec(CaffeineSpec caffeineSpec) {
doSetCaffeine(Caffeine.from(caffeineSpec)); doSetCaffeine(Caffeine.from(caffeineSpec));
@ -132,7 +132,7 @@ public class CaffeineCacheManager implements CacheManager {
* individual {@link CaffeineCache} instance. The given value needs to * individual {@link CaffeineCache} instance. The given value needs to
* comply with Caffeine's {@link CaffeineSpec} (see its javadoc). * comply with Caffeine's {@link CaffeineSpec} (see its javadoc).
* @see #createNativeCaffeineCache * @see #createNativeCaffeineCache
* @see com.github.benmanes.caffeine.cache.Caffeine#from(String) * @see Caffeine#from(String)
*/ */
public void setCacheSpecification(String cacheSpecification) { public void setCacheSpecification(String cacheSpecification) {
doSetCaffeine(Caffeine.from(cacheSpecification)); doSetCaffeine(Caffeine.from(cacheSpecification));
@ -149,7 +149,7 @@ public class CaffeineCacheManager implements CacheManager {
* Set the Caffeine CacheLoader to use for building each individual * Set the Caffeine CacheLoader to use for building each individual
* {@link CaffeineCache} instance, turning it into a LoadingCache. * {@link CaffeineCache} instance, turning it into a LoadingCache.
* @see #createNativeCaffeineCache * @see #createNativeCaffeineCache
* @see com.github.benmanes.caffeine.cache.Caffeine#build(CacheLoader) * @see Caffeine#build(CacheLoader)
* @see com.github.benmanes.caffeine.cache.LoadingCache * @see com.github.benmanes.caffeine.cache.LoadingCache
*/ */
public void setCacheLoader(CacheLoader<Object, Object> cacheLoader) { public void setCacheLoader(CacheLoader<Object, Object> cacheLoader) {

28
spring-context-support/src/test/java/org/springframework/cache/caffeine/CaffeineCacheManagerTests.java vendored

@ -38,19 +38,17 @@ public class CaffeineCacheManagerTests {
@Test @Test
public void testDynamicMode() { public void testDynamicMode() {
CacheManager cm = new CaffeineCacheManager(); CacheManager cm = new CaffeineCacheManager();
Cache cache1 = cm.getCache("c1"); Cache cache1 = cm.getCache("c1");
boolean condition2 = cache1 instanceof CaffeineCache; assertThat(cache1).isInstanceOf(CaffeineCache.class);
assertThat(condition2).isTrue();
Cache cache1again = cm.getCache("c1"); Cache cache1again = cm.getCache("c1");
assertThat(cache1).isSameAs(cache1again); assertThat(cache1).isSameAs(cache1again);
Cache cache2 = cm.getCache("c2"); Cache cache2 = cm.getCache("c2");
boolean condition1 = cache2 instanceof CaffeineCache; assertThat(cache2).isInstanceOf(CaffeineCache.class);
assertThat(condition1).isTrue();
Cache cache2again = cm.getCache("c2"); Cache cache2again = cm.getCache("c2");
assertThat(cache2).isSameAs(cache2again); assertThat(cache2).isSameAs(cache2again);
Cache cache3 = cm.getCache("c3"); Cache cache3 = cm.getCache("c3");
boolean condition = cache3 instanceof CaffeineCache; assertThat(cache3).isInstanceOf(CaffeineCache.class);
assertThat(condition).isTrue();
Cache cache3again = cm.getCache("c3"); Cache cache3again = cm.getCache("c3");
assertThat(cache3).isSameAs(cache3again); assertThat(cache3).isSameAs(cache3again);
@ -62,19 +60,23 @@ public class CaffeineCacheManagerTests {
assertThat(cache1.get("key3").get()).isNull(); assertThat(cache1.get("key3").get()).isNull();
cache1.evict("key3"); cache1.evict("key3");
assertThat(cache1.get("key3")).isNull(); assertThat(cache1.get("key3")).isNull();
assertThat(cache1.get("key3", () -> "value3")).isEqualTo("value3");
assertThat(cache1.get("key3", () -> "value3")).isEqualTo("value3");
cache1.evict("key3");
assertThat(cache1.get("key3", () -> (String) null)).isNull();
assertThat(cache1.get("key3", () -> (String) null)).isNull();
} }
@Test @Test
public void testStaticMode() { public void testStaticMode() {
CaffeineCacheManager cm = new CaffeineCacheManager("c1", "c2"); CaffeineCacheManager cm = new CaffeineCacheManager("c1", "c2");
Cache cache1 = cm.getCache("c1"); Cache cache1 = cm.getCache("c1");
boolean condition3 = cache1 instanceof CaffeineCache; assertThat(cache1).isInstanceOf(CaffeineCache.class);
assertThat(condition3).isTrue();
Cache cache1again = cm.getCache("c1"); Cache cache1again = cm.getCache("c1");
assertThat(cache1).isSameAs(cache1again); assertThat(cache1).isSameAs(cache1again);
Cache cache2 = cm.getCache("c2"); Cache cache2 = cm.getCache("c2");
boolean condition2 = cache2 instanceof CaffeineCache; assertThat(cache2).isInstanceOf(CaffeineCache.class);
assertThat(condition2).isTrue();
Cache cache2again = cm.getCache("c2"); Cache cache2again = cm.getCache("c2");
assertThat(cache2).isSameAs(cache2again); assertThat(cache2).isSameAs(cache2again);
Cache cache3 = cm.getCache("c3"); Cache cache3 = cm.getCache("c3");
@ -91,12 +93,10 @@ public class CaffeineCacheManagerTests {
cm.setAllowNullValues(false); cm.setAllowNullValues(false);
Cache cache1x = cm.getCache("c1"); Cache cache1x = cm.getCache("c1");
boolean condition1 = cache1x instanceof CaffeineCache; assertThat(cache1x).isInstanceOf(CaffeineCache.class);
assertThat(condition1).isTrue();
assertThat(cache1x).isNotSameAs(cache1); assertThat(cache1x).isNotSameAs(cache1);
Cache cache2x = cm.getCache("c2"); Cache cache2x = cm.getCache("c2");
boolean condition = cache2x instanceof CaffeineCache; assertThat(cache2x).isInstanceOf(CaffeineCache.class);
assertThat(condition).isTrue();
assertThat(cache2x).isNotSameAs(cache2); assertThat(cache2x).isNotSameAs(cache2);
Cache cache3x = cm.getCache("c3"); Cache cache3x = cm.getCache("c3");
assertThat(cache3x).isNull(); assertThat(cache3x).isNull();

14
spring-context/src/main/java/org/springframework/cache/Cache.java vendored

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,14 +23,20 @@ import org.springframework.lang.Nullable;
/** /**
* Interface that defines common cache operations. * Interface that defines common cache operations.
* *
* <b>Note:</b> Due to the generic use of caching, it is recommended that * <p>Serves as an SPI for Spring's annotation-based caching model
* implementations allow storage of {@code null} values (for example to * ({@link org.springframework.cache.annotation.Cacheable} and co)
* cache methods that return {@code null}). * as well as an API for direct usage in applications.
*
* <p><b>Note:</b> Due to the generic use of caching, it is recommended
* that implementations allow storage of {@code null} values
* (for example to cache methods that return {@code null}).
* *
* @author Costin Leau * @author Costin Leau
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 3.1 * @since 3.1
* @see CacheManager
* @see org.springframework.cache.annotation.Cacheable
*/ */
public interface Cache { public interface Cache {

8
spring-context/src/main/java/org/springframework/cache/interceptor/AbstractCacheInvoker.java vendored

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -82,12 +82,12 @@ public abstract class AbstractCacheInvoker {
* Execute {@link Cache#put(Object, Object)} on the specified {@link Cache} * Execute {@link Cache#put(Object, Object)} on the specified {@link Cache}
* and invoke the error handler if an exception occurs. * and invoke the error handler if an exception occurs.
*/ */
protected void doPut(Cache cache, Object key, @Nullable Object result) { protected void doPut(Cache cache, Object key, @Nullable Object value) {
try { try {
cache.put(key, result); cache.put(key, value);
} }
catch (RuntimeException ex) { catch (RuntimeException ex) {
getErrorHandler().handleCachePutError(ex, cache, key, result); getErrorHandler().handleCachePutError(ex, cache, key, value);
} }
} }

22
spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java vendored

@ -397,11 +397,11 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
processCacheEvicts(contexts.get(CacheEvictOperation.class), true, processCacheEvicts(contexts.get(CacheEvictOperation.class), true,
CacheOperationExpressionEvaluator.NO_RESULT); CacheOperationExpressionEvaluator.NO_RESULT);
// Check if we have a cached item matching the conditions // Check if we have a cached value matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class)); Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any @Cacheable miss, if no cached item is found // Collect puts from any @Cacheable miss, if no cached value is found
List<CachePutRequest> cachePutRequests = new ArrayList<>(); List<CachePutRequest> cachePutRequests = new ArrayList<>(1);
if (cacheHit == null) { if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class), collectPutRequests(contexts.get(CacheableOperation.class),
CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests); CacheOperationExpressionEvaluator.NO_RESULT, cachePutRequests);
@ -468,7 +468,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
private boolean hasCachePut(CacheOperationContexts contexts) { private boolean hasCachePut(CacheOperationContexts contexts) {
// Evaluate the conditions *without* the result object because we don't have it yet... // Evaluate the conditions *without* the result object because we don't have it yet...
Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class); Collection<CacheOperationContext> cachePutContexts = contexts.get(CachePutOperation.class);
Collection<CacheOperationContext> excluded = new ArrayList<>(); Collection<CacheOperationContext> excluded = new ArrayList<>(1);
for (CacheOperationContext context : cachePutContexts) { for (CacheOperationContext context : cachePutContexts) {
try { try {
if (!context.isConditionPassing(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE)) { if (!context.isConditionPassing(CacheOperationExpressionEvaluator.RESULT_UNAVAILABLE)) {
@ -521,9 +521,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
} }
/** /**
* Find a cached item only for {@link CacheableOperation} that passes the condition. * Find a cached value only for {@link CacheableOperation} that passes the condition.
* @param contexts the cacheable operations * @param contexts the cacheable operations
* @return a {@link Cache.ValueWrapper} holding the cached item, * @return a {@link Cache.ValueWrapper} holding the cached value,
* or {@code null} if none is found * or {@code null} if none is found
*/ */
@Nullable @Nullable
@ -548,9 +548,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
/** /**
* Collect the {@link CachePutRequest} for all {@link CacheOperation} using * Collect the {@link CachePutRequest} for all {@link CacheOperation} using
* the specified result item. * the specified result value.
* @param contexts the contexts to handle * @param contexts the contexts to handle
* @param result the result item (never {@code null}) * @param result the result value (never {@code null})
* @param putRequests the collection to update * @param putRequests the collection to update
*/ */
private void collectPutRequests(Collection<CacheOperationContext> contexts, private void collectPutRequests(Collection<CacheOperationContext> contexts,
@ -721,7 +721,7 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
this.args = extractArgs(metadata.method, args); this.args = extractArgs(metadata.method, args);
this.target = target; this.target = target;
this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver); this.caches = CacheAspectSupport.this.getCaches(this, metadata.cacheResolver);
this.cacheNames = createCacheNames(this.caches); this.cacheNames = prepareCacheNames(this.caches);
} }
@Override @Override
@ -809,8 +809,8 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
return this.cacheNames; return this.cacheNames;
} }
private Collection<String> createCacheNames(Collection<? extends Cache> caches) { private Collection<String> prepareCacheNames(Collection<? extends Cache> caches) {
Collection<String> names = new ArrayList<>(); Collection<String> names = new ArrayList<>(caches.size());
for (Cache cache : caches) { for (Cache cache : caches) {
names.add(cache.getName()); names.add(cache.getName());
} }

8
spring-context/src/main/java/org/springframework/cache/support/SimpleCacheManager.java vendored

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,14 +24,16 @@ import org.springframework.cache.Cache;
/** /**
* Simple cache manager working against a given collection of caches. * Simple cache manager working against a given collection of caches.
* Useful for testing or simple caching declarations. * Useful for testing or simple caching declarations.
* <p> *
* When using this implementation directly, i.e. not via a regular * <p>When using this implementation directly, i.e. not via a regular
* bean registration, {@link #initializeCaches()} should be invoked * bean registration, {@link #initializeCaches()} should be invoked
* to initialize its internal state once the * to initialize its internal state once the
* {@linkplain #setCaches(Collection) caches have been provided}. * {@linkplain #setCaches(Collection) caches have been provided}.
* *
* @author Costin Leau * @author Costin Leau
* @since 3.1 * @since 3.1
* @see NoOpCache
* @see org.springframework.cache.concurrent.ConcurrentMapCache
*/ */
public class SimpleCacheManager extends AbstractCacheManager { public class SimpleCacheManager extends AbstractCacheManager {

4
spring-context/src/test/java/org/springframework/cache/CacheReproTests.java vendored

@ -118,6 +118,7 @@ class CacheReproTests {
assertThat(cacheResolver.getCache("foo").get("foo")).isNull(); assertThat(cacheResolver.getCache("foo").get("foo")).isNull();
Object result = bean.getSimple("foo"); // cache name = id Object result = bean.getSimple("foo"); // cache name = id
assertThat(cacheResolver.getCache("foo").get("foo").get()).isEqualTo(result); assertThat(cacheResolver.getCache("foo").get("foo").get()).isEqualTo(result);
context.close(); context.close();
} }
@ -146,6 +147,7 @@ class CacheReproTests {
TestBean tb2 = bean.findById("tb1").get(); TestBean tb2 = bean.findById("tb1").get();
assertThat(tb2).isNotSameAs(tb); assertThat(tb2).isNotSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb2); assertThat(cache.get("tb1").get()).isSameAs(tb2);
context.close(); context.close();
} }
@ -177,6 +179,7 @@ class CacheReproTests {
bean.insertItem(tb); bean.insertItem(tb);
assertThat(bean.findById("tb1").get()).isSameAs(tb); assertThat(bean.findById("tb1").get()).isSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb); assertThat(cache.get("tb1").get()).isSameAs(tb);
context.close(); context.close();
} }
@ -190,6 +193,7 @@ class CacheReproTests {
bean.insertItem(tb); bean.insertItem(tb);
assertThat(bean.findById("tb1").get()).isSameAs(tb); assertThat(bean.findById("tb1").get()).isSameAs(tb);
assertThat(cache.get("tb1").get()).isSameAs(tb); assertThat(cache.get("tb1").get()).isSameAs(tb);
context.close(); context.close();
} }

Loading…
Cancel
Save