/*
 * Copyright 2002-2016 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
 *
 *      http://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.support;

import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.lang.Nullable;

Abstract base class implementing the common CacheManager methods. Useful for 'static' environments where the backing caches do not change.
Author:Costin Leau, Juergen Hoeller, Stephane Nicoll
Since:3.1
/** * Abstract base class implementing the common {@link CacheManager} methods. * Useful for 'static' environments where the backing caches do not change. * * @author Costin Leau * @author Juergen Hoeller * @author Stephane Nicoll * @since 3.1 */
public abstract class AbstractCacheManager implements CacheManager, InitializingBean { private final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>(16); private volatile Set<String> cacheNames = Collections.emptySet(); // Early cache initialization on startup @Override public void afterPropertiesSet() { initializeCaches(); }
Initialize the static configuration of caches.

Triggered on startup through afterPropertiesSet(); can also be called to re-initialize at runtime.

See Also:
Since:4.2.2
/** * Initialize the static configuration of caches. * <p>Triggered on startup through {@link #afterPropertiesSet()}; * can also be called to re-initialize at runtime. * @since 4.2.2 * @see #loadCaches() */
public void initializeCaches() { Collection<? extends Cache> caches = loadCaches(); synchronized (this.cacheMap) { this.cacheNames = Collections.emptySet(); this.cacheMap.clear(); Set<String> cacheNames = new LinkedHashSet<>(caches.size()); for (Cache cache : caches) { String name = cache.getName(); this.cacheMap.put(name, decorateCache(cache)); cacheNames.add(name); } this.cacheNames = Collections.unmodifiableSet(cacheNames); } }
Load the initial caches for this cache manager.

Called by afterPropertiesSet() on startup. The returned collection may be empty but must not be null.

/** * Load the initial caches for this cache manager. * <p>Called by {@link #afterPropertiesSet()} on startup. * The returned collection may be empty but must not be {@code null}. */
protected abstract Collection<? extends Cache> loadCaches(); // Lazy cache initialization on access @Override @Nullable public Cache getCache(String name) { Cache cache = this.cacheMap.get(name); if (cache != null) { return cache; } else { // Fully synchronize now for missing cache creation... synchronized (this.cacheMap) { cache = this.cacheMap.get(name); if (cache == null) { cache = getMissingCache(name); if (cache != null) { cache = decorateCache(cache); this.cacheMap.put(name, cache); updateCacheNames(name); } } return cache; } } } @Override public Collection<String> getCacheNames() { return this.cacheNames; } // Common cache initialization delegates for subclasses
Check for a registered cache of the given name. In contrast to getCache(String), this method does not trigger the lazy creation of missing caches via getMissingCache(String).
Params:
  • name – the cache identifier (must not be null)
See Also:
Returns:the associated Cache instance, or null if none found
Since:4.1
/** * Check for a registered cache of the given name. * In contrast to {@link #getCache(String)}, this method does not trigger * the lazy creation of missing caches via {@link #getMissingCache(String)}. * @param name the cache identifier (must not be {@code null}) * @return the associated Cache instance, or {@code null} if none found * @since 4.1 * @see #getCache(String) * @see #getMissingCache(String) */
@Nullable protected final Cache lookupCache(String name) { return this.cacheMap.get(name); }
Dynamically register an additional Cache with this manager.
Params:
  • cache – the Cache to register
Deprecated:as of Spring 4.3, in favor of getMissingCache(String)
/** * Dynamically register an additional Cache with this manager. * @param cache the Cache to register * @deprecated as of Spring 4.3, in favor of {@link #getMissingCache(String)} */
@Deprecated protected final void addCache(Cache cache) { String name = cache.getName(); synchronized (this.cacheMap) { if (this.cacheMap.put(name, decorateCache(cache)) == null) { updateCacheNames(name); } } }
Update the exposed cacheNames set with the given name.

This will always be called within a full cacheMap lock and effectively behaves like a CopyOnWriteArraySet with preserved order but exposed as an unmodifiable reference.

Params:
  • name – the name of the cache to be added
/** * Update the exposed {@link #cacheNames} set with the given name. * <p>This will always be called within a full {@link #cacheMap} lock * and effectively behaves like a {@code CopyOnWriteArraySet} with * preserved order but exposed as an unmodifiable reference. * @param name the name of the cache to be added */
private void updateCacheNames(String name) { Set<String> cacheNames = new LinkedHashSet<>(this.cacheNames.size() + 1); cacheNames.addAll(this.cacheNames); cacheNames.add(name); this.cacheNames = Collections.unmodifiableSet(cacheNames); } // Overridable template methods for cache initialization
Decorate the given Cache object if necessary.
Params:
  • cache – the Cache object to be added to this CacheManager
Returns:the decorated Cache object to be used instead, or simply the passed-in Cache object by default
/** * Decorate the given Cache object if necessary. * @param cache the Cache object to be added to this CacheManager * @return the decorated Cache object to be used instead, * or simply the passed-in Cache object by default */
protected Cache decorateCache(Cache cache) { return cache; }
Return a missing cache with the specified name or null if such cache does not exist or could not be created on the fly.

Some caches may be created at runtime if the native provider supports it. If a lookup by name does not yield any result, a subclass gets a chance to register such a cache at runtime. The returned cache will be automatically added to this instance.

Params:
  • name – the name of the cache to retrieve
See Also:
Returns:the missing cache or null if no such cache exists or could be created
Since:4.1
/** * Return a missing cache with the specified {@code name} or {@code null} if * such cache does not exist or could not be created on the fly. * <p>Some caches may be created at runtime if the native provider supports * it. If a lookup by name does not yield any result, a subclass gets a chance * to register such a cache at runtime. The returned cache will be automatically * added to this instance. * @param name the name of the cache to retrieve * @return the missing cache or {@code null} if no such cache exists or could be * created * @since 4.1 * @see #getCache(String) */
@Nullable protected Cache getMissingCache(String name) { return null; } }