/*
* Copyright 2002-2019 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.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) {
// Quick check for existing cache...
Cache cache = this.cacheMap.get(name);
if (cache != null) {
return cache;
}
// The provider may support on-demand cache creation...
Cache missingCache = getMissingCache(name);
if (missingCache != null) {
// Fully synchronize now for missing cache registration
synchronized (this.cacheMap) {
cache = this.cacheMap.get(name);
if (cache == null) {
cache = decorateCache(missingCache);
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);
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 a cache does not exist or could not be created on demand. Caches may be lazily created at runtime if the native provider supports it. If a lookup by name does not yield any result, an AbstractCacheManager
subclass gets a chance to register such a cache at runtime. The returned cache will be automatically added to this cache manager.
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 on demand Since: 4.1
/**
* Return a missing cache with the specified {@code name}, or {@code null} if
* such a cache does not exist or could not be created on demand.
* <p>Caches may be lazily created at runtime if the native provider supports it.
* If a lookup by name does not yield any result, an {@code AbstractCacheManager}
* subclass gets a chance to register such a cache at runtime. The returned cache
* will be automatically added to this cache manager.
* @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 on demand
* @since 4.1
* @see #getCache(String)
*/
@Nullable
protected Cache getMissingCache(String name) {
return null;
}
}