All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.cache.Cache Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2002-2023 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.cache;

import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;

import org.springframework.lang.Nullable;

/**
 * Interface that defines common cache operations.
 *
 * 

Serves primarily as an SPI for Spring's annotation-based caching * model ({@link org.springframework.cache.annotation.Cacheable} and co) * and secondarily as an API for direct usage in applications. * *

Note: 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 Juergen Hoeller * @author Stephane Nicoll * @since 3.1 * @see CacheManager * @see org.springframework.cache.annotation.Cacheable */ public interface Cache { /** * Return the cache name. */ String getName(); /** * Return the underlying native cache provider. */ Object getNativeCache(); /** * Return the value to which this cache maps the specified key. *

Returns {@code null} if the cache contains no mapping for this key; * otherwise, the cached value (which may be {@code null} itself) will * be returned in a {@link ValueWrapper}. * @param key the key whose associated value is to be returned * @return the value to which this cache maps the specified key, * contained within a {@link ValueWrapper} which may also hold * a cached {@code null} value. A straight {@code null} being * returned means that the cache contains no mapping for this key. * @see #get(Object, Class) * @see #get(Object, Callable) */ @Nullable ValueWrapper get(Object key); /** * Return the value to which this cache maps the specified key, * generically specifying a type that return value will be cast to. *

Note: This variant of {@code get} does not allow for differentiating * between a cached {@code null} value and no cache entry found at all. * Use the standard {@link #get(Object)} variant for that purpose instead. * @param key the key whose associated value is to be returned * @param type the required type of the returned value (may be * {@code null} to bypass a type check; in case of a {@code null} * value found in the cache, the specified type is irrelevant) * @return the value to which this cache maps the specified key * (which may be {@code null} itself), or also {@code null} if * the cache contains no mapping for this key * @throws IllegalStateException if a cache entry has been found * but failed to match the specified type * @since 4.0 * @see #get(Object) */ @Nullable T get(Object key, @Nullable Class type); /** * Return the value to which this cache maps the specified key, obtaining * that value from {@code valueLoader} if necessary. This method provides * a simple substitute for the conventional "if cached, return; otherwise * create, cache and return" pattern. *

If possible, implementations should ensure that the loading operation * is synchronized so that the specified {@code valueLoader} is only called * once in case of concurrent access on the same key. *

If the {@code valueLoader} throws an exception, it is wrapped in * a {@link ValueRetrievalException} * @param key the key whose associated value is to be returned * @return the value to which this cache maps the specified key * @throws ValueRetrievalException if the {@code valueLoader} throws an exception * @since 4.3 * @see #get(Object) */ @Nullable T get(Object key, Callable valueLoader); /** * Return the value to which this cache maps the specified key, * wrapped in a {@link CompletableFuture}. This operation must not block * but is allowed to return a completed {@link CompletableFuture} if the * corresponding value is immediately available. *

Can return {@code null} if the cache can immediately determine that * it contains no mapping for this key (for example, through an in-memory key map). * Otherwise, the cached value will be returned in the {@link CompletableFuture}, * with {@code null} indicating a late-determined cache miss. A nested * {@link ValueWrapper} potentially indicates a nullable cached value; * the cached value may also be represented as a plain element if null * values are not supported. Calling code needs to be prepared to handle * all those variants of the result returned by this method. * @param key the key whose associated value is to be returned * @return the value to which this cache maps the specified key, contained * within a {@link CompletableFuture} which may also be empty when a cache * miss has been late-determined. A straight {@code null} being returned * means that the cache immediately determined that it contains no mapping * for this key. A {@link ValueWrapper} contained within the * {@code CompletableFuture} indicates a cached value that is potentially * {@code null}; this is sensible in a late-determined scenario where a regular * CompletableFuture-contained {@code null} indicates a cache miss. However, * a cache may also return a plain value if it does not support the actual * caching of {@code null} values, avoiding the extra level of value wrapping. * Spring's cache processing can deal with all such implementation strategies. * @since 6.1 * @see #retrieve(Object, Supplier) */ @Nullable default CompletableFuture retrieve(Object key) { throw new UnsupportedOperationException( getClass().getName() + " does not support CompletableFuture-based retrieval"); } /** * Return the value to which this cache maps the specified key, obtaining * that value from {@code valueLoader} if necessary. This method provides * a simple substitute for the conventional "if cached, return; otherwise * create, cache and return" pattern, based on {@link CompletableFuture}. * This operation must not block. *

If possible, implementations should ensure that the loading operation * is synchronized so that the specified {@code valueLoader} is only called * once in case of concurrent access on the same key. *

Null values always indicate a user-level {@code null} value with this * method. The provided {@link CompletableFuture} handle produces a value * or raises an exception. If the {@code valueLoader} raises an exception, * it will be propagated to the returned {@code CompletableFuture} handle. * @param key the key whose associated value is to be returned * @return the value to which this cache maps the specified key, contained * within a {@link CompletableFuture} which will never be {@code null}. * The provided future is expected to produce a value or raise an exception. * @since 6.1 * @see #retrieve(Object) * @see #get(Object, Callable) */ default CompletableFuture retrieve(Object key, Supplier> valueLoader) { throw new UnsupportedOperationException( getClass().getName() + " does not support CompletableFuture-based retrieval"); } /** * Associate the specified value with the specified key in this cache. *

If the cache previously contained a mapping for this key, the old * value is replaced by the specified value. *

Actual registration may be performed in an asynchronous or deferred * fashion, with subsequent lookups possibly not seeing the entry yet. * This may for example be the case with transactional cache decorators. * Use {@link #putIfAbsent} for guaranteed immediate registration. *

If the cache is supposed to be compatible with {@link CompletableFuture} * and reactive interactions, the put operation needs to be effectively * non-blocking, with any backend write-through happening asynchronously. * This goes along with a cache implemented and configured to support * {@link #retrieve(Object)} and {@link #retrieve(Object, Supplier)}. * @param key the key with which the specified value is to be associated * @param value the value to be associated with the specified key * @see #putIfAbsent(Object, Object) */ void put(Object key, @Nullable Object value); /** * Atomically associate the specified value with the specified key in this cache * if it is not set already. *

This is equivalent to: *


	 * ValueWrapper existingValue = cache.get(key);
	 * if (existingValue == null) {
	 *     cache.put(key, value);
	 * }
	 * return existingValue;
	 * 
* except that the action is performed atomically. While all out-of-the-box * {@link CacheManager} implementations are able to perform the put atomically, * the operation may also be implemented in two steps, for example, with a check for * presence and a subsequent put, in a non-atomic way. Check the documentation * of the native cache implementation that you are using for more details. *

The default implementation delegates to {@link #get(Object)} and * {@link #put(Object, Object)} along the lines of the code snippet above. * @param key the key with which the specified value is to be associated * @param value the value to be associated with the specified key * @return the value to which this cache maps the specified key (which may be * {@code null} itself), or also {@code null} if the cache did not contain any * mapping for that key prior to this call. Returning {@code null} is therefore * an indicator that the given {@code value} has been associated with the key. * @since 4.1 * @see #put(Object, Object) */ @Nullable default ValueWrapper putIfAbsent(Object key, @Nullable Object value) { ValueWrapper existingValue = get(key); if (existingValue == null) { put(key, value); } return existingValue; } /** * Evict the mapping for this key from this cache if it is present. *

Actual eviction may be performed in an asynchronous or deferred * fashion, with subsequent lookups possibly still seeing the entry. * This may for example be the case with transactional cache decorators. * Use {@link #evictIfPresent} for guaranteed immediate removal. *

If the cache is supposed to be compatible with {@link CompletableFuture} * and reactive interactions, the evict operation needs to be effectively * non-blocking, with any backend write-through happening asynchronously. * This goes along with a cache implemented and configured to support * {@link #retrieve(Object)} and {@link #retrieve(Object, Supplier)}. * @param key the key whose mapping is to be removed from the cache * @see #evictIfPresent(Object) */ void evict(Object key); /** * Evict the mapping for this key from this cache if it is present, * expecting the key to be immediately invisible for subsequent lookups. *

The default implementation delegates to {@link #evict(Object)}, * returning {@code false} for not-determined prior presence of the key. * Cache providers and in particular cache decorators are encouraged * to perform immediate eviction if possible (for example, in case of generally * deferred cache operations within a transaction) and to reliably * determine prior presence of the given key. * @param key the key whose mapping is to be removed from the cache * @return {@code true} if the cache was known to have a mapping for * this key before, {@code false} if it did not (or if prior presence * could not be determined) * @since 5.2 * @see #evict(Object) */ default boolean evictIfPresent(Object key) { evict(key); return false; } /** * Clear the cache through removing all mappings. *

Actual clearing may be performed in an asynchronous or deferred * fashion, with subsequent lookups possibly still seeing the entries. * This may for example be the case with transactional cache decorators. * Use {@link #invalidate()} for guaranteed immediate removal of entries. *

If the cache is supposed to be compatible with {@link CompletableFuture} * and reactive interactions, the clear operation needs to be effectively * non-blocking, with any backend write-through happening asynchronously. * This goes along with a cache implemented and configured to support * {@link #retrieve(Object)} and {@link #retrieve(Object, Supplier)}. * @see #invalidate() */ void clear(); /** * Invalidate the cache through removing all mappings, expecting all * entries to be immediately invisible for subsequent lookups. * @return {@code true} if the cache was known to have mappings before, * {@code false} if it did not (or if prior presence of entries could * not be determined) * @since 5.2 * @see #clear() */ default boolean invalidate() { clear(); return false; } /** * A (wrapper) object representing a cache value. */ @FunctionalInterface interface ValueWrapper { /** * Return the actual value in the cache. */ @Nullable Object get(); } /** * Wrapper exception to be thrown from {@link #get(Object, Callable)} * in case of the value loader callback failing with an exception. * @since 4.3 */ @SuppressWarnings("serial") class ValueRetrievalException extends RuntimeException { @Nullable private final Object key; public ValueRetrievalException(@Nullable Object key, Callable loader, @Nullable Throwable ex) { super(String.format("Value for key '%s' could not be loaded using '%s'", key, loader), ex); this.key = key; } @Nullable public Object getKey() { return this.key; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy