+ update aspectj cache aspects

+ update integration tests
This commit is contained in:
Costin Leau 2011-11-28 13:05:59 +00:00
parent 1e2f49104d
commit d10f2258e8
7 changed files with 717 additions and 30 deletions

View File

@ -18,7 +18,9 @@ package org.springframework.cache.aspectj;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Concrete AspectJ cache aspect using Spring's @{@link Cacheable} annotation.
@ -59,6 +61,20 @@ public aspect AnnotationCacheAspect extends AbstractCacheAspect {
private pointcut executionOfAnyPublicMethodInAtCacheEvictType() :
execution(public * ((@CacheEvict *)+).*(..)) && @this(CacheEvict);
/**
* Matches the execution of any public method in a type with the @{@link CachePut}
* annotation, or any subtype of a type with the {@code CachePut} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachePutType() :
execution(public * ((@CachePut *)+).*(..)) && @this(CachePut);
/**
* Matches the execution of any public method in a type with the @{@link Caching}
* annotation, or any subtype of a type with the {@code Caching} annotation.
*/
private pointcut executionOfAnyPublicMethodInAtCachingType() :
execution(public * ((@Caching *)+).*(..)) && @this(Caching);
/**
* Matches the execution of any method with the @{@link Cacheable} annotation.
*/
@ -71,6 +87,18 @@ public aspect AnnotationCacheAspect extends AbstractCacheAspect {
private pointcut executionOfCacheEvictMethod() :
execution(* *(..)) && @annotation(CacheEvict);
/**
* Matches the execution of any method with the @{@link CachePut} annotation.
*/
private pointcut executionOfCachePutMethod() :
execution(* *(..)) && @annotation(CachePut);
/**
* Matches the execution of any method with the @{@link Caching} annotation.
*/
private pointcut executionOfCachingMethod() :
execution(* *(..)) && @annotation(Caching);
/**
* Definition of pointcut from super aspect - matched join points will have Spring
* cache management applied.
@ -78,8 +106,11 @@ public aspect AnnotationCacheAspect extends AbstractCacheAspect {
protected pointcut cacheMethodExecution(Object cachedObject) :
(executionOfAnyPublicMethodInAtCacheableType()
|| executionOfAnyPublicMethodInAtCacheEvictType()
|| executionOfAnyPublicMethodInAtCachePutType()
|| executionOfAnyPublicMethodInAtCachingType()
|| executionOfCacheableMethod()
|| executionOfCacheEvictMethod())
|| executionOfCacheEvictMethod()
|| executionOfCachePutMethod()
|| executionOfCachingMethod())
&& this(cachedObject);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* 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.
@ -18,38 +18,48 @@ package org.springframework.cache.aspectj;
import static org.junit.Assert.*;
import java.util.Collection;
import java.util.UUID;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.config.AnnotatedClassCacheableService;
import org.springframework.cache.config.CacheableService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Abstract annotation test (containing several reusable methods).
*
* @author Costin Leau
* @author Chris Beams
*/
public abstract class AbstractAnnotationTest {
protected ApplicationContext ctx;
protected CacheableService cs;
protected CacheableService<?> cs;
protected CacheableService ccs;
protected CacheableService<?> ccs;
protected abstract String getConfig();
protected CacheManager cm;
/** @return a refreshed application context */
protected abstract ApplicationContext getApplicationContext();
@Before
public void setup() {
ctx = new ClassPathXmlApplicationContext(getConfig());
ctx = getApplicationContext();
cs = ctx.getBean("service", CacheableService.class);
ccs = ctx.getBean("classService", CacheableService.class);
cm = ctx.getBean(CacheManager.class);
Collection<String> cn = cm.getCacheNames();
assertTrue(cn.contains("default"));
}
public void testCacheable(CacheableService service) throws Exception {
public void testCacheable(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object o2 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
@ -59,9 +69,8 @@ public abstract class AbstractAnnotationTest {
assertSame(r1, r3);
}
public void testInvalidate(CacheableService service) throws Exception {
public void testEvict(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object o2 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
@ -74,7 +83,98 @@ public abstract class AbstractAnnotationTest {
assertSame(r3, r4);
}
public void testConditionalExpression(CacheableService service) throws Exception {
public void testEvictEarly(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
assertSame(r1, r2);
try {
service.evictEarly(o1);
} catch (RuntimeException ex) {
// expected
}
Object r3 = service.cache(o1);
Object r4 = service.cache(o1);
assertNotSame(r1, r3);
assertSame(r3, r4);
}
public void testEvictException(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
assertSame(r1, r2);
try {
service.evictWithException(o1);
} catch (RuntimeException ex) {
// expected
}
// exception occurred, eviction skipped, data should still be in the cache
Object r3 = service.cache(o1);
assertSame(r1, r3);
}
public void testEvictWKey(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
assertSame(r1, r2);
service.evict(o1, null);
Object r3 = service.cache(o1);
Object r4 = service.cache(o1);
assertNotSame(r1, r3);
assertSame(r3, r4);
}
public void testEvictWKeyEarly(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
assertSame(r1, r2);
try {
service.invalidateEarly(o1, null);
} catch (Exception ex) {
// expected
}
Object r3 = service.cache(o1);
Object r4 = service.cache(o1);
assertNotSame(r1, r3);
assertSame(r3, r4);
}
public void testEvictAll(CacheableService<?> service) throws Exception {
Object o1 = new Object();
Object r1 = service.cache(o1);
Object r2 = service.cache(o1);
Object o2 = new Object();
Object r10 = service.cache(o2);
assertSame(r1, r2);
assertNotSame(r1, r10);
service.evictAll(new Object());
Cache cache = cm.getCache("default");
assertNull(cache.get(o1));
assertNull(cache.get(o2));
Object r3 = service.cache(o1);
Object r4 = service.cache(o1);
assertNotSame(r1, r3);
assertSame(r3, r4);
}
public void testConditionalExpression(CacheableService<?> service) throws Exception {
Object r1 = service.conditional(4);
Object r2 = service.conditional(4);
@ -86,7 +186,7 @@ public abstract class AbstractAnnotationTest {
assertSame(r3, r4);
}
public void testKeyExpression(CacheableService service) throws Exception {
public void testKeyExpression(CacheableService<?> service) throws Exception {
Object r1 = service.key(5, 1);
Object r2 = service.key(5, 2);
@ -98,7 +198,26 @@ public abstract class AbstractAnnotationTest {
assertNotSame(r3, r4);
}
public void testCheckedThrowable(CacheableService service) throws Exception {
public void testNullValue(CacheableService<?> service) throws Exception {
Object key = new Object();
assertNull(service.nullValue(key));
int nr = service.nullInvocations().intValue();
assertNull(service.nullValue(key));
assertEquals(nr, service.nullInvocations().intValue());
assertNull(service.nullValue(new Object()));
assertEquals(nr + 1, service.nullInvocations().intValue());
}
public void testMethodName(CacheableService<?> service, String keyName) throws Exception {
Object key = new Object();
Object r1 = service.name(key);
assertSame(r1, service.name(key));
Cache cache = cm.getCache("default");
// assert the method name is used
assertNotNull(cache.get(keyName));
}
public void testCheckedThrowable(CacheableService<?> service) throws Exception {
String arg = UUID.randomUUID().toString();
try {
service.throwChecked(arg);
@ -108,16 +227,165 @@ public abstract class AbstractAnnotationTest {
}
}
public void testUncheckedThrowable(CacheableService service) throws Exception {
public void testUncheckedThrowable(CacheableService<?> service) throws Exception {
try {
service.throwUnchecked(Long.valueOf(1));
fail("Excepted exception");
} catch (RuntimeException ex) {
assertTrue(ex instanceof UnsupportedOperationException);
assertTrue("Excepted different exception type and got " + ex.getClass(),
ex instanceof UnsupportedOperationException);
// expected
}
}
public void testNullArg(CacheableService<?> service) {
Object r1 = service.cache(null);
assertSame(r1, service.cache(null));
}
public void testCacheUpdate(CacheableService<?> service) {
Object o = new Object();
Cache cache = cm.getCache("default");
assertNull(cache.get(o));
Object r1 = service.update(o);
assertSame(r1, cache.get(o).get());
o = new Object();
assertNull(cache.get(o));
Object r2 = service.update(o);
assertSame(r2, cache.get(o).get());
}
public void testConditionalCacheUpdate(CacheableService<?> service) {
Integer one = Integer.valueOf(1);
Integer three = Integer.valueOf(3);
Cache cache = cm.getCache("default");
assertEquals(one, Integer.valueOf(service.conditionalUpdate(one).toString()));
assertNull(cache.get(one));
assertEquals(three, Integer.valueOf(service.conditionalUpdate(three).toString()));
assertEquals(three, Integer.valueOf(cache.get(three).get().toString()));
}
public void testMultiCache(CacheableService<?> service) {
Object o1 = new Object();
Object o2 = new Object();
Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary");
assertNull(primary.get(o1));
assertNull(secondary.get(o1));
Object r1 = service.multiCache(o1);
assertSame(r1, primary.get(o1).get());
assertSame(r1, secondary.get(o1).get());
Object r2 = service.multiCache(o1);
Object r3 = service.multiCache(o1);
assertSame(r1, r2);
assertSame(r1, r3);
assertNull(primary.get(o2));
assertNull(secondary.get(o2));
Object r4 = service.multiCache(o2);
assertSame(r4, primary.get(o2).get());
assertSame(r4, secondary.get(o2).get());
}
public void testMultiEvict(CacheableService<?> service) {
Object o1 = new Object();
Object r1 = service.multiCache(o1);
Object r2 = service.multiCache(o1);
Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary");
assertSame(r1, r2);
assertSame(r1, primary.get(o1).get());
assertSame(r1, secondary.get(o1).get());
service.multiEvict(o1);
assertNull(primary.get(o1));
assertNull(secondary.get(o1));
Object r3 = service.multiCache(o1);
Object r4 = service.multiCache(o1);
assertNotSame(r1, r3);
assertSame(r3, r4);
assertSame(r3, primary.get(o1).get());
assertSame(r4, secondary.get(o1).get());
}
public void testMultiPut(CacheableService<?> service) {
Object o = Integer.valueOf(1);
Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary");
assertNull(primary.get(o));
assertNull(secondary.get(o));
Object r1 = service.multiUpdate(o);
assertSame(r1, primary.get(o).get());
assertSame(r1, secondary.get(o).get());
o = Integer.valueOf(2);
assertNull(primary.get(o));
assertNull(secondary.get(o));
Object r2 = service.multiUpdate(o);
assertSame(r2, primary.get(o).get());
assertSame(r2, secondary.get(o).get());
}
public void testMultiCacheAndEvict(CacheableService<?> service) {
String methodName = "multiCacheAndEvict";
Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary");
Object key = Integer.valueOf(1);
secondary.put(key, key);
assertNull(secondary.get(methodName));
assertSame(key, secondary.get(key).get());
Object r1 = service.multiCacheAndEvict(key);
assertSame(r1, service.multiCacheAndEvict(key));
// assert the method name is used
assertSame(r1, primary.get(methodName).get());
assertNull(secondary.get(methodName));
assertNull(secondary.get(key));
}
public void testMultiConditionalCacheAndEvict(CacheableService<?> service) {
Cache primary = cm.getCache("primary");
Cache secondary = cm.getCache("secondary");
Object key = Integer.valueOf(1);
secondary.put(key, key);
assertNull(primary.get(key));
assertSame(key, secondary.get(key).get());
Object r1 = service.multiConditionalCacheAndEvict(key);
Object r3 = service.multiConditionalCacheAndEvict(key);
assertTrue(!r1.equals(r3));
assertNull(primary.get(key));
Object key2 = Integer.valueOf(3);
Object r2 = service.multiConditionalCacheAndEvict(key2);
assertSame(r2, service.multiConditionalCacheAndEvict(key2));
// assert the method name is used
assertSame(r2, primary.get(key2).get());
assertNull(secondary.get(key2));
}
@Test
public void testCacheable() throws Exception {
testCacheable(cs);
@ -125,7 +393,32 @@ public abstract class AbstractAnnotationTest {
@Test
public void testInvalidate() throws Exception {
testInvalidate(cs);
testEvict(cs);
}
@Test
public void testEarlyInvalidate() throws Exception {
testEvictEarly(cs);
}
@Test
public void testEvictWithException() throws Exception {
testEvictException(cs);
}
@Test
public void testEvictAll() throws Exception {
testEvictAll(cs);
}
@Test
public void testInvalidateWithKey() throws Exception {
testEvictWKey(cs);
}
@Test
public void testEarlyInvalidateWithKey() throws Exception {
testEvictWKeyEarly(cs);
}
@Test
@ -145,7 +438,70 @@ public abstract class AbstractAnnotationTest {
@Test
public void testClassCacheInvalidate() throws Exception {
testInvalidate(ccs);
testEvict(ccs);
}
@Test
public void testClassEarlyInvalidate() throws Exception {
testEvictEarly(ccs);
}
@Test
public void testClassEvictAll() throws Exception {
testEvictAll(ccs);
}
@Test
public void testClassEvictWithException() throws Exception {
testEvictException(ccs);
}
@Test
public void testClassCacheInvalidateWKey() throws Exception {
testEvictWKey(ccs);
}
@Test
public void testClassEarlyInvalidateWithKey() throws Exception {
testEvictWKeyEarly(ccs);
}
@Test
public void testNullValue() throws Exception {
testNullValue(cs);
}
@Test
public void testClassNullValue() throws Exception {
Object key = new Object();
assertNull(ccs.nullValue(key));
int nr = ccs.nullInvocations().intValue();
assertNull(ccs.nullValue(key));
assertEquals(nr, ccs.nullInvocations().intValue());
assertNull(ccs.nullValue(new Object()));
// the check method is also cached
assertEquals(nr, ccs.nullInvocations().intValue());
assertEquals(nr + 1, AnnotatedClassCacheableService.nullInvocations.intValue());
}
@Test
public void testMethodName() throws Exception {
testMethodName(cs, "name");
}
@Test
public void testClassMethodName() throws Exception {
testMethodName(ccs, "namedefault");
}
@Test
public void testNullArg() throws Exception {
testNullArg(cs);
}
@Test
public void testClassNullArg() throws Exception {
testNullArg(ccs);
}
@Test
@ -168,4 +524,73 @@ public abstract class AbstractAnnotationTest {
testUncheckedThrowable(ccs);
}
@Test
public void testUpdate() {
testCacheUpdate(cs);
}
@Test
public void testClassUpdate() {
testCacheUpdate(ccs);
}
@Test
public void testConditionalUpdate() {
testConditionalCacheUpdate(cs);
}
@Test
public void testClassConditionalUpdate() {
testConditionalCacheUpdate(ccs);
}
@Test
public void testMultiCache() {
testMultiCache(cs);
}
@Test
public void testClassMultiCache() {
testMultiCache(ccs);
}
@Test
public void testMultiEvict() {
testMultiEvict(cs);
}
@Test
public void testClassMultiEvict() {
testMultiEvict(ccs);
}
@Test
public void testMultiPut() {
testMultiPut(cs);
}
@Test
public void testClassMultiPut() {
testMultiPut(ccs);
}
@Test
public void testMultiCacheAndEvict() {
testMultiCacheAndEvict(cs);
}
@Test
public void testClassMultiCacheAndEvict() {
testMultiCacheAndEvict(ccs);
}
@Test
public void testMultiConditionalCacheAndEvict() {
testMultiConditionalCacheAndEvict(cs);
}
@Test
public void testClassMultiConditionalCacheAndEvict() {
testMultiConditionalCacheAndEvict(ccs);
}
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2010 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.aspectj;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
/**
* @author Costin Leau
*/
public class AspectJAnnotationTest extends AbstractAnnotationTest {
@Override
protected ApplicationContext getApplicationContext() {
return new GenericXmlApplicationContext("/org/springframework/cache/config/annotation-cache-aspectj.xml");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* 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.
@ -19,15 +19,18 @@ package org.springframework.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* @author Costin Leau
*/
@Cacheable("default")
public class AnnotatedClassCacheableService implements CacheableService {
public class AnnotatedClassCacheableService implements CacheableService<Object> {
private AtomicLong counter = new AtomicLong();
private final AtomicLong counter = new AtomicLong();
public static final AtomicLong nullInvocations = new AtomicLong();
public Object cache(Object arg1) {
return counter.getAndIncrement();
@ -41,11 +44,63 @@ public class AnnotatedClassCacheableService implements CacheableService {
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", afterInvocation = false)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", afterInvocation = false)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", key = "#p0")
public Object key(Object arg1, Object arg2) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.caches[0].name")
public Object name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Object rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Object update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Object conditionalUpdate(Object arg) {
return arg;
}
public Object nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
public Long throwChecked(Object arg1) throws Exception {
throw new UnsupportedOperationException(arg1.toString());
}
@ -53,4 +108,31 @@ public class AnnotatedClassCacheableService implements CacheableService {
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException();
}
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Object multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Object multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Object multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Object multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Object multiUpdate(Object arg1) {
return arg1;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* 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.
@ -16,7 +16,6 @@
package org.springframework.cache.config;
/**
* Basic service interface.
*
@ -28,11 +27,44 @@ public interface CacheableService<T> {
void invalidate(Object arg1);
void evictEarly(Object arg1);
void evictAll(Object arg1);
void evictWithException(Object arg1);
void evict(Object arg1, Object arg2);
void invalidateEarly(Object arg1, Object arg2);
T conditional(int field);
T key(Object arg1, Object arg2);
T name(Object arg1);
T nullValue(Object arg1);
T update(Object arg1);
T conditionalUpdate(Object arg2);
Number nullInvocations();
T rootVars(Object arg1);
T throwChecked(Object arg1) throws Exception;
T throwUnchecked(Object arg1);
// multi annotations
T multiCache(Object arg1);
T multiEvict(Object arg1);
T multiCacheAndEvict(Object arg1);
T multiConditionalCacheAndEvict(Object arg1);
T multiUpdate(Object arg1);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2010 the original author or authors.
* 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.
@ -19,8 +19,9 @@ package org.springframework.cache.config;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
/**
* Simple cacheable service
@ -29,7 +30,8 @@ import org.springframework.cache.annotation.Cacheable;
*/
public class DefaultCacheableService implements CacheableService<Long> {
private AtomicLong counter = new AtomicLong();
private final AtomicLong counter = new AtomicLong();
private final AtomicLong nullInvocations = new AtomicLong();
@Cacheable("default")
public Long cache(Object arg1) {
@ -40,6 +42,29 @@ public class DefaultCacheableService implements CacheableService<Long> {
public void invalidate(Object arg1) {
}
@CacheEvict("default")
public void evictWithException(Object arg1) {
throw new RuntimeException("exception thrown - evict should NOT occur");
}
@CacheEvict(value = "default", allEntries = true)
public void evictAll(Object arg1) {
}
@CacheEvict(value = "default", afterInvocation = false)
public void evictEarly(Object arg1) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@CacheEvict(value = "default", key = "#p0")
public void evict(Object arg1, Object arg2) {
}
@CacheEvict(value = "default", key = "#p0", afterInvocation = false)
public void invalidateEarly(Object arg1, Object arg2) {
throw new RuntimeException("exception thrown - evict should still occur");
}
@Cacheable(value = "default", condition = "#classField == 3")
public Long conditional(int classField) {
return counter.getAndIncrement();
@ -50,6 +75,36 @@ public class DefaultCacheableService implements CacheableService<Long> {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName")
public Long name(Object arg1) {
return counter.getAndIncrement();
}
@Cacheable(value = "default", key = "#root.methodName + #root.method.name + #root.targetClass + #root.target")
public Long rootVars(Object arg1) {
return counter.getAndIncrement();
}
@CachePut("default")
public Long update(Object arg1) {
return counter.getAndIncrement();
}
@CachePut(value = "default", condition = "#arg.equals(3)")
public Long conditionalUpdate(Object arg) {
return Long.valueOf(arg.toString());
}
@Cacheable("default")
public Long nullValue(Object arg1) {
nullInvocations.incrementAndGet();
return null;
}
public Number nullInvocations() {
return nullInvocations.get();
}
@Cacheable("default")
public Long throwChecked(Object arg1) throws Exception {
throw new Exception(arg1.toString());
@ -59,4 +114,31 @@ public class DefaultCacheableService implements CacheableService<Long> {
public Long throwUnchecked(Object arg1) {
throw new UnsupportedOperationException(arg1.toString());
}
// multi annotations
@Caching(cacheable = { @Cacheable("primary"), @Cacheable("secondary") })
public Long multiCache(Object arg1) {
return counter.getAndIncrement();
}
@Caching(evict = { @CacheEvict("primary"), @CacheEvict(value = "secondary", key = "#p0") })
public Long multiEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", key = "#root.methodName") }, evict = { @CacheEvict("secondary") })
public Long multiCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(cacheable = { @Cacheable(value = "primary", condition = "#p0 == 3") }, evict = { @CacheEvict("secondary") })
public Long multiConditionalCacheAndEvict(Object arg1) {
return counter.getAndIncrement();
}
@Caching(put = { @CachePut("primary"), @CachePut("secondary") })
public Long multiUpdate(Object arg1) {
return Long.valueOf(arg1.toString());
}
}

View File

@ -13,13 +13,15 @@
<bean id="cacheAspect" class="org.springframework.cache.aspectj.AnnotationCacheAspect" factory-method="aspectOf">
<property name="cacheManager" ref="cacheManager"/>
<property name="cacheOperationSource" ref="annotationSource"/>
<property name="cacheOperationSources" ref="annotationSource"/>
</bean>
<bean id="cacheManager" class="org.springframework.cache.support.SimpleCacheManager">
<property name="caches">
<set>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="default"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="primary"/>
<bean class="org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean" p:name="secondary"/>
</set>
</property>
</bean>