Browse Source
In the course of this enhancement, the "cache.ehcache" and "cache.jcache" packages moved from spring-context to the spring-context-support module, expecting further transaction-related functionality. Also aligns with the presence of Spring's Quartz support in the spring-context-support module, since Quartz and EHCache are sort of sister projects at Terracotta now. Issue: SPR-9966pull/188/head
20 changed files with 404 additions and 101 deletions
@ -0,0 +1,61 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2012 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.transaction; |
||||||
|
|
||||||
|
import org.springframework.cache.Cache; |
||||||
|
import org.springframework.cache.support.AbstractCacheManager; |
||||||
|
|
||||||
|
/** |
||||||
|
* Base class for CacheManager implementations that want to support built-in |
||||||
|
* awareness of Spring-managed transactions. This usually needs to be switched |
||||||
|
* on explicitly through the {@link #setTransactionAware} bean property. |
||||||
|
* |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 3.2 |
||||||
|
* @see #setTransactionAware |
||||||
|
* @see TransactionAwareCacheDecorator |
||||||
|
* @see TransactionAwareCacheManagerProxy |
||||||
|
*/ |
||||||
|
public abstract class AbstractTransactionSupportingCacheManager extends AbstractCacheManager { |
||||||
|
|
||||||
|
private boolean transactionAware = false; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set whether this CacheManager should expose transaction-aware Cache objects. |
||||||
|
* <p>Default is "false". Set this to "true" to synchronize cache put/evict |
||||||
|
* operations with ongoing Spring-managed transactions, performing the actual cache |
||||||
|
* put/evict operation only in the after-commit phase of a successful transaction. |
||||||
|
*/ |
||||||
|
public void setTransactionAware(boolean transactionAware) { |
||||||
|
this.transactionAware = transactionAware; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return whether this CacheManager has been configured to be transaction-aware. |
||||||
|
*/ |
||||||
|
public boolean isTransactionAware() { |
||||||
|
return this.transactionAware; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
protected Cache decorateCache(Cache cache) { |
||||||
|
return (isTransactionAware() ? new TransactionAwareCacheDecorator(cache) : cache); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,94 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2012 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.transaction; |
||||||
|
|
||||||
|
import org.springframework.cache.Cache; |
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationAdapter; |
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Cache decorator which synchronizes its {@link #put} and {@link #evict} operations with |
||||||
|
* Spring-managed transactions (through Spring's {@link TransactionSynchronizationManager}, |
||||||
|
* performing the actual cache put/evict operation only in the after-commit phase of a |
||||||
|
* successful transaction. If no transaction is active, {@link #put} and {@link #evict} |
||||||
|
* operations will be performed immediately, as usual. |
||||||
|
* |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 3.2 |
||||||
|
* @see TransactionAwareCacheManagerProxy |
||||||
|
*/ |
||||||
|
public class TransactionAwareCacheDecorator implements Cache { |
||||||
|
|
||||||
|
private final Cache targetCache; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new TransactionAwareCache for the given target Cache. |
||||||
|
* @param targetCache the target Cache to decorate |
||||||
|
*/ |
||||||
|
public TransactionAwareCacheDecorator(Cache targetCache) { |
||||||
|
Assert.notNull(targetCache, "Target Cache must not be null"); |
||||||
|
this.targetCache = targetCache; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return this.targetCache.getName(); |
||||||
|
} |
||||||
|
|
||||||
|
public Object getNativeCache() { |
||||||
|
return this.targetCache.getNativeCache(); |
||||||
|
} |
||||||
|
|
||||||
|
public ValueWrapper get(Object key) { |
||||||
|
return this.targetCache.get(key); |
||||||
|
} |
||||||
|
|
||||||
|
public void put(final Object key, final Object value) { |
||||||
|
if (TransactionSynchronizationManager.isSynchronizationActive()) { |
||||||
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { |
||||||
|
@Override |
||||||
|
public void afterCommit() { |
||||||
|
targetCache.put(key, value); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.targetCache.put(key, value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void evict(final Object key) { |
||||||
|
if (TransactionSynchronizationManager.isSynchronizationActive()) { |
||||||
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { |
||||||
|
@Override |
||||||
|
public void afterCommit() { |
||||||
|
targetCache.evict(key); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.targetCache.evict(key); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void clear() { |
||||||
|
this.targetCache.clear(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,83 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2012 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.transaction; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.InitializingBean; |
||||||
|
import org.springframework.cache.Cache; |
||||||
|
import org.springframework.cache.CacheManager; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* Proxy for a target {@link CacheManager}, exposing transaction-aware {@link Cache} objects |
||||||
|
* which synchronize their {@link Cache#put} operations with Spring-managed transactions |
||||||
|
* (through Spring's {@link org.springframework.transaction.support.TransactionSynchronizationManager}, |
||||||
|
* performing the actual cache put operation only in the after-commit phase of a successful transaction. |
||||||
|
* If no transaction is active, {@link Cache#put} operations will be performed immediately, as usual. |
||||||
|
* |
||||||
|
* @author Juergen Hoeller |
||||||
|
* @since 3.2 |
||||||
|
* @see #setTargetCacheManager |
||||||
|
* @see TransactionAwareCacheDecorator |
||||||
|
* @see org.springframework.transaction.support.TransactionSynchronizationManager |
||||||
|
*/ |
||||||
|
public class TransactionAwareCacheManagerProxy implements CacheManager, InitializingBean { |
||||||
|
|
||||||
|
private CacheManager targetCacheManager; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new TransactionAwareCacheManagerProxy, setting the target CacheManager |
||||||
|
* through the {@link #setTargetCacheManager} bean property. |
||||||
|
*/ |
||||||
|
public TransactionAwareCacheManagerProxy() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new TransactionAwareCacheManagerProxy for the given target CacheManager. |
||||||
|
* @param targetCacheManager the target CacheManager to proxy |
||||||
|
*/ |
||||||
|
public TransactionAwareCacheManagerProxy(CacheManager targetCacheManager) { |
||||||
|
Assert.notNull(targetCacheManager, "Target CacheManager must not be null"); |
||||||
|
this.targetCacheManager = targetCacheManager; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Set the target CacheManager to proxy. |
||||||
|
*/ |
||||||
|
public void setTargetCacheManager(CacheManager targetCacheManager) { |
||||||
|
this.targetCacheManager = targetCacheManager; |
||||||
|
} |
||||||
|
|
||||||
|
public void afterPropertiesSet() { |
||||||
|
if (this.targetCacheManager == null) { |
||||||
|
throw new IllegalStateException("'targetCacheManager' is required"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Cache getCache(String name) { |
||||||
|
return new TransactionAwareCacheDecorator(this.targetCacheManager.getCache(name)); |
||||||
|
} |
||||||
|
|
||||||
|
public Collection<String> getCacheNames() { |
||||||
|
return this.targetCacheManager.getCacheNames(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,5 @@ |
|||||||
|
/** |
||||||
|
* Transaction-aware decorators for the the org.springframework.cache package. |
||||||
|
* Provides synchronization of put operations with Spring-managed transactions. |
||||||
|
*/ |
||||||
|
package org.springframework.cache.transaction; |
||||||
@ -1,62 +0,0 @@ |
|||||||
/* |
|
||||||
* Copyright 2010-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.ehcache; |
|
||||||
|
|
||||||
import static org.junit.Assert.*; |
|
||||||
import net.sf.ehcache.Ehcache; |
|
||||||
import net.sf.ehcache.Element; |
|
||||||
|
|
||||||
import org.junit.Test; |
|
||||||
import org.springframework.cache.Cache; |
|
||||||
import org.springframework.cache.vendor.AbstractNativeCacheTests; |
|
||||||
|
|
||||||
/** |
|
||||||
* Integration test for EhCache cache. |
|
||||||
* |
|
||||||
* @author Costin Leau |
|
||||||
*/ |
|
||||||
public class EhCacheCacheTests extends AbstractNativeCacheTests<Ehcache> { |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Ehcache createNativeCache() throws Exception { |
|
||||||
EhCacheFactoryBean fb = new EhCacheFactoryBean(); |
|
||||||
fb.setBeanName(CACHE_NAME); |
|
||||||
fb.setCacheName(CACHE_NAME); |
|
||||||
fb.afterPropertiesSet(); |
|
||||||
return fb.getObject(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected Cache createCache(Ehcache nativeCache) { |
|
||||||
return new EhCacheCache(nativeCache); |
|
||||||
} |
|
||||||
|
|
||||||
@Test |
|
||||||
public void testExpiredElements() throws Exception { |
|
||||||
String key = "brancusi"; |
|
||||||
String value = "constantin"; |
|
||||||
Element brancusi = new Element(key, value); |
|
||||||
// ttl = 10s
|
|
||||||
brancusi.setTimeToLive(3); |
|
||||||
nativeCache.put(brancusi); |
|
||||||
|
|
||||||
assertEquals(value, cache.get(key).get()); |
|
||||||
// wait for the entry to expire
|
|
||||||
Thread.sleep(5 * 1000); |
|
||||||
assertNull(cache.get(key)); |
|
||||||
} |
|
||||||
} |
|
||||||
Loading…
Reference in new issue