+ add no-op cache implementations suitable for cache declarations w/o a backing store

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@4641 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
Costin Leau 2011-06-30 18:17:39 +00:00
parent 783d4077a6
commit 08fc4f9015
4 changed files with 209 additions and 4 deletions

View File

@ -21,6 +21,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.util.Assert;
@ -29,11 +30,21 @@ import org.springframework.util.Assert;
* Composite {@link CacheManager} implementation that iterates
* over a given collection of {@link CacheManager} instances.
*
* Allows {@link NoOpCacheManager} to be automatically added to the list for handling
* the cache declarations without a backing store.
*
* @author Costin Leau
*/
public class CompositeCacheManager implements CacheManager {
public class CompositeCacheManager implements InitializingBean, CacheManager {
private CacheManager[] cacheManagers;
private List<CacheManager> cacheManagers;
private boolean noOpManager = false;
public void afterPropertiesSet() {
if (noOpManager) {
cacheManagers.add(new NoOpCacheManager());
}
}
public Cache getCache(String name) {
Cache cache = null;
@ -55,8 +66,20 @@ public class CompositeCacheManager implements CacheManager {
return Collections.unmodifiableCollection(names);
}
public void setCacheManagers(CacheManager[] cacheManagers) {
public void setCacheManagers(Collection<CacheManager> cacheManagers) {
Assert.notEmpty(cacheManagers, "non-null/empty array required");
this.cacheManagers = cacheManagers.clone();
this.cacheManagers = new ArrayList<CacheManager>();
this.cacheManagers.addAll(cacheManagers);
}
/**
* Indicates whether a {@link NoOpCacheManager} will be added at the end of the manager lists.
* Any cache requests not handled by the configured cache managers will be automatically handled
* by the {@link NoOpCacheManager}.
*
* @param add whether a {@link NoOpCacheManager} instance will be added or not
*/
public void setAddNoOpCache(boolean add) {
this.noOpManager = add;
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright 2011 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.cache.Cache;
import org.springframework.cache.CacheManager;
/**
* A basic, no operation {@link CacheManager} implementation suitable for disabling caching,
* typically used for backing cache declarations without an actual backing store.
*
* Will simply accept any items into the cache not actually storing them.
*
* @see CompositeCacheManager
* @author Costin Leau
*/
public class NoOpCacheManager implements CacheManager {
private final ConcurrentMap<String, Cache> caches = new ConcurrentHashMap<String, Cache>();
private Set<String> names = new LinkedHashSet<String>();
private static class NoOpCache implements Cache {
private final String name;
public NoOpCache(String name) {
this.name = name;
}
public void clear() {
}
public void evict(Object key) {
}
public ValueWrapper get(Object key) {
return null;
}
public String getName() {
return name;
}
public Object getNativeCache() {
return null;
}
public void put(Object key, Object value) {
}
}
/**
* {@inheritDoc}
*
* This implementation always returns a {@link Cache} implementation that will not
* store items. Additionally, the request cache will be remembered by the manager for consistency.
*/
public Cache getCache(String name) {
Cache cache = caches.get(name);
if (cache == null) {
caches.putIfAbsent(name, new NoOpCache(name));
synchronized (names) {
names.add(name);
}
}
return caches.get(name);
}
/**
* {@inheritDoc}
*
* This implementation returns the name of the caches previously requested.
*/
public Collection<String> getCacheNames() {
return Collections.unmodifiableSet(names);
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2011 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;
import static org.junit.Assert.*;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cache.support.NoOpCacheManager;
public class NoOpCacheManagerTest {
private CacheManager manager;
@Before
public void setup() {
manager = new NoOpCacheManager();
}
@Test
public void testGetCache() throws Exception {
Cache cache = manager.getCache("bucket");
assertNotNull(cache);
assertSame(cache, manager.getCache("bucket"));
}
@Test
public void testNoOpCache() throws Exception {
String name = UUID.randomUUID().toString();
Cache cache = manager.getCache(name);
assertEquals(name, cache.getName());
Object key = new Object();
cache.put(key, new Object());
assertNull(cache.get(key));
assertNull(cache.getNativeCache());
}
@Test
public void testCacheName() throws Exception {
String name = "bucket";
assertFalse(manager.getCacheNames().contains(name));
manager.getCache(name);
assertTrue(manager.getCacheNames().contains(name));
}
}

View File

@ -383,6 +383,7 @@ public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)]]><
</section>
</section>
<section id="cache-store-configuration">
<title>Configuring the cache storage</title>
@ -429,6 +430,27 @@ public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)]]><
implementation. Note the entire ehcache-specific configuration is read from the resource <literal>ehcache.xml</literal>.</para>
</section>
<section id="cache-store-configuration-noop">
<title>Dealing with caches without a backing store</title>
<para>Sometimes when switching environments or doing testing, one might have cache declarations without an actual backing cache configured. As this is an invalid configuration, at runtime an
exception will be through since the caching infrastructure is unable to find a suitable store. In situations like this, rather then removing the cache declarations (which can prove tedious),
one can wire in a simple, dummy cache that performs no caching - that is, forces the cached methods to be executed every time:</para>
<programlisting language="xml"><![CDATA[<bean id="cacheManager" class="org.springframework.cache.support.CompositeCacheManager">
<property name="cacheManagers"><list>
<ref bean="jdkCache"/>
<ref bean="gemfireCache"/>
</list></property>
<property name="addNoOpCache" value="true"/>
</bean>]]></programlisting>
<para>The <literal>CompositeCacheManager</literal> above chains multiple <literal>CacheManager</literal>s and aditionally, through the <literal>addNoOpManager</literal> flag, adds a
<emphasis>no op</emphasis> cache that for all the definitions not handled by the configured cache managers. That is, every cache definition not found in either <literal>jdkCache</literal>
or <literal>gemfireCache</literal> (configured above) will be handled by the no op cache, which will not store any information causing the target method to be executed every time.
</para>
</section>
</section>
<section id="cache-plug">