下面列出了怎么用org.springframework.cache.interceptor.CacheOperation的API类实例代码及写法,或者点击链接到github查看源代码。
@Nullable
private Collection<CacheOperation> parseCacheAnnotations(
DefaultCacheConfig cachingConfig, AnnotatedElement ae, boolean localOnly) {
Collection<? extends Annotation> anns = (localOnly ?
AnnotatedElementUtils.getAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS) :
AnnotatedElementUtils.findAllMergedAnnotations(ae, CACHE_OPERATION_ANNOTATIONS));
if (anns.isEmpty()) {
return null;
}
final Collection<CacheOperation> ops = new ArrayList<>(1);
anns.stream().filter(ann -> ann instanceof Cacheable).forEach(
ann -> ops.add(parseCacheableAnnotation(ae, cachingConfig, (Cacheable) ann)));
anns.stream().filter(ann -> ann instanceof CacheEvict).forEach(
ann -> ops.add(parseEvictAnnotation(ae, cachingConfig, (CacheEvict) ann)));
anns.stream().filter(ann -> ann instanceof CachePut).forEach(
ann -> ops.add(parsePutAnnotation(ae, cachingConfig, (CachePut) ann)));
anns.stream().filter(ann -> ann instanceof Caching).forEach(
ann -> parseCachingAnnotation(ae, cachingConfig, (Caching) ann, ops));
return ops;
}
private CacheOperation parsePutAnnotation(
AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {
CachePutOperation.Builder builder = new CachePutOperation.Builder();
builder.setName(ae.toString());
builder.setCacheNames(cachePut.cacheNames());
builder.setCondition(cachePut.condition());
builder.setUnless(cachePut.unless());
builder.setKey(cachePut.key());
builder.setKeyGenerator(cachePut.keyGenerator());
builder.setCacheManager(cachePut.cacheManager());
builder.setCacheResolver(cachePut.cacheResolver());
defaultConfig.applyDefault(builder);
CachePutOperation op = builder.build();
validateCacheOperation(ae, op);
return op;
}
/**
* Validates the specified {@link CacheOperation}.
* <p>Throws an {@link IllegalStateException} if the state of the operation is
* invalid. As there might be multiple sources for default values, this ensure
* that the operation is in a proper state before being returned.
* @param ae the annotated element of the cache operation
* @param operation the {@link CacheOperation} to validate
*/
private void validateCacheOperation(AnnotatedElement ae, CacheOperation operation) {
if (StringUtils.hasText(operation.getKey()) && StringUtils.hasText(operation.getKeyGenerator())) {
throw new IllegalStateException("Invalid cache annotation configuration on '" +
ae.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " +
"These attributes are mutually exclusive: either set the SpEL expression used to" +
"compute the key at runtime or set the name of the KeyGenerator bean to use.");
}
if (StringUtils.hasText(operation.getCacheManager()) && StringUtils.hasText(operation.getCacheResolver())) {
throw new IllegalStateException("Invalid cache annotation configuration on '" +
ae.toString() + "'. Both 'cacheManager' and 'cacheResolver' attributes have been set. " +
"These attributes are mutually exclusive: the cache manager is used to configure a" +
"default cache resolver if none is set. If a cache resolver is set, the cache manager" +
"won't be used.");
}
}
@Test
public void multipleComposedAnnotations() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 4);
Iterator<CacheOperation> it = ops.iterator();
CacheOperation cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("directly declared")));
assertThat(cacheOperation.getKey(), equalTo(""));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
assertThat(cacheOperation.getKey(), equalTo("composedKey"));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("foo")));
assertThat(cacheOperation.getKey(), equalTo(""));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheEvictOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCacheEvict")));
assertThat(cacheOperation.getKey(), equalTo("composedEvictionKey"));
}
CacheOperation parsePutAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {
CachePutOperation.Builder builder = new CachePutOperation.Builder();
builder.setName(ae.toString());
builder.setCacheNames(cachePut.cacheNames());
builder.setCondition(cachePut.condition());
builder.setUnless(cachePut.unless());
builder.setKey(cachePut.key());
builder.setKeyGenerator(cachePut.keyGenerator());
builder.setCacheManager(cachePut.cacheManager());
builder.setCacheResolver(cachePut.cacheResolver());
defaultConfig.applyDefault(builder);
CachePutOperation op = builder.build();
validateCacheOperation(ae, op);
return op;
}
/**
* Determine the caching attribute for this method invocation.
* <p>Defaults to the class's caching attribute if no method attribute is found.
*
* @param method the method for the current invocation (never {@code null})
* @param targetClass the target class for this invocation (may be {@code null})
* @return {@link CacheOperation} for this method, or {@code null} if the method
* is not cacheable
*/
@Override
public Collection<CacheOperation> getCacheOperations(Method method, Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}
Object cacheKey = getCacheKey(method, targetClass);
Collection<CacheOperation> cached = this.attributeCache.get(cacheKey);
if (cached != null) {
return (cached != NULL_CACHING_ATTRIBUTE ? cached : null);
} else {
Collection<CacheOperation> cacheOps = computeCacheOperations(method, targetClass);
if (cacheOps != null) {
if (logger.isDebugEnabled()) {
logger.debug("Adding cacheable method '" + method.getName() + "' with attribute: " + cacheOps);
}
this.attributeCache.put(cacheKey, cacheOps);
} else {
this.attributeCache.put(cacheKey, NULL_CACHING_ATTRIBUTE);
}
return cacheOps;
}
}
/**
* Apply the defaults to the specified {@link CacheOperation.Builder}.
*
* @param builder the operation builder to update
*/
public void applyDefault(CacheOperation.Builder builder) {
if (builder.getCacheNames().isEmpty() && this.cacheNames != null) {
builder.setCacheNames(this.cacheNames);
}
if (!StringUtils.hasText(builder.getKey()) && !StringUtils.hasText(builder.getKeyGenerator()) &&
StringUtils.hasText(this.keyGenerator)) {
builder.setKeyGenerator(this.keyGenerator);
}
if (StringUtils.hasText(builder.getCacheManager()) || StringUtils.hasText(builder.getCacheResolver())) {
// One of these is set so we should not inherit anything
} else if (StringUtils.hasText(this.cacheResolver)) {
builder.setCacheResolver(this.cacheResolver);
} else if (StringUtils.hasText(this.cacheManager)) {
builder.setCacheManager(this.cacheManager);
}
}
/**
* Determine the cache operation(s) for the given {@link CacheOperationProvider}.
* <p>This implementation delegates to configured
* {@link CacheAnnotationParser CacheAnnotationParsers}
* for parsing known annotations into Spring's metadata attribute class.
* <p>Can be overridden to support custom annotations that carry caching metadata.
* @param provider the cache operation provider to use
* @return the configured caching operations, or {@code null} if none found
*/
@Nullable
protected Collection<CacheOperation> determineCacheOperations(CacheOperationProvider provider) {
Collection<CacheOperation> ops = null;
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
Collection<CacheOperation> annOps = provider.getCacheOperations(annotationParser);
if (annOps != null) {
if (ops == null) {
ops = annOps;
}
else {
Collection<CacheOperation> combined = new ArrayList<>(ops.size() + annOps.size());
combined.addAll(ops);
combined.addAll(annOps);
ops = combined;
}
}
}
return ops;
}
@Ignore("Disabled until SPR-13475 is resolved")
@Test
public void multipleComposedAnnotations() throws Exception {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 3);
Iterator<CacheOperation> it = ops.iterator();
CacheOperation cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("foo")));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheEvictOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
}
private CacheOperation parsePutAnnotation(
AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {
CachePutOperation.Builder builder = new CachePutOperation.Builder();
builder.setName(ae.toString());
builder.setCacheNames(cachePut.cacheNames());
builder.setCondition(cachePut.condition());
builder.setUnless(cachePut.unless());
builder.setKey(cachePut.key());
builder.setKeyGenerator(cachePut.keyGenerator());
builder.setCacheManager(cachePut.cacheManager());
builder.setCacheResolver(cachePut.cacheResolver());
defaultConfig.applyDefault(builder);
CachePutOperation op = builder.build();
validateCacheOperation(ae, op);
return op;
}
CacheOperation parsePutAnnotation(AnnotatedElement ae, DefaultCacheConfig defaultConfig, CachePut cachePut) {
CachePutOperation op = new CachePutOperation();
op.setCacheNames(cachePut.cacheNames());
op.setCondition(cachePut.condition());
op.setUnless(cachePut.unless());
op.setKey(cachePut.key());
op.setKeyGenerator(cachePut.keyGenerator());
op.setCacheManager(cachePut.cacheManager());
op.setCacheResolver(cachePut.cacheResolver());
op.setName(ae.toString());
defaultConfig.applyDefault(op);
validateCacheOperation(ae, op);
return op;
}
@Test
public void multipleComposedAnnotations() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multipleComposed", 4);
Iterator<CacheOperation> it = ops.iterator();
CacheOperation cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("directly declared")));
assertThat(cacheOperation.getKey(), equalTo(""));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
assertThat(cacheOperation.getKey(), equalTo("composedKey"));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("foo")));
assertThat(cacheOperation.getKey(), equalTo(""));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheEvictOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCacheEvict")));
assertThat(cacheOperation.getKey(), equalTo("composedEvictionKey"));
}
/**
* Validates the specified {@link CacheOperation}.
* <p>Throws an {@link IllegalStateException} if the state of the operation is
* invalid. As there might be multiple sources for default values, this ensure
* that the operation is in a proper state before being returned.
*
* @param ae the annotated element of the cache operation
* @param operation the {@link CacheOperation} to validate
*/
private void validateCacheOperation(AnnotatedElement ae, CacheOperation operation) {
if (StringUtils.hasText(operation.getKey()) && StringUtils.hasText(operation.getKeyGenerator())) {
throw new IllegalStateException("Invalid cache annotation configuration on '" +
ae.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " +
"These attributes are mutually exclusive: either set the SpEL expression used to" +
"compute the key at runtime or set the name of the KeyGenerator bean to use.");
}
if (StringUtils.hasText(operation.getCacheManager()) && StringUtils.hasText(operation.getCacheResolver())) {
throw new IllegalStateException("Invalid cache annotation configuration on '" +
ae.toString() + "'. Both 'cacheManager' and 'cacheResolver' attributes have been set. " +
"These attributes are mutually exclusive: the cache manager is used to configure a" +
"default cache resolver if none is set. If a cache resolver is set, the cache manager" +
"won't be used.");
}
}
@Test
public void validateNoCacheIsValid() {
// Valid as a CacheResolver might return the cache names to use with other info
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "noCacheNameSpecified");
CacheOperation cacheOperation = ops.iterator().next();
assertNotNull("cache names set must not be null", cacheOperation.getCacheNames());
assertEquals("no cache names specified", 0, cacheOperation.getCacheNames().size());
}
/**
* Apply the defaults to the specified {@link CacheOperation.Builder}.
* @param builder the operation builder to update
*/
public void applyDefault(CacheOperation.Builder builder) {
if (!this.initialized) {
CacheConfig annotation = AnnotatedElementUtils.findMergedAnnotation(this.target, CacheConfig.class);
if (annotation != null) {
this.cacheNames = annotation.cacheNames();
this.keyGenerator = annotation.keyGenerator();
this.cacheManager = annotation.cacheManager();
this.cacheResolver = annotation.cacheResolver();
}
this.initialized = true;
}
if (builder.getCacheNames().isEmpty() && this.cacheNames != null) {
builder.setCacheNames(this.cacheNames);
}
if (!StringUtils.hasText(builder.getKey()) && !StringUtils.hasText(builder.getKeyGenerator()) &&
StringUtils.hasText(this.keyGenerator)) {
builder.setKeyGenerator(this.keyGenerator);
}
if (StringUtils.hasText(builder.getCacheManager()) || StringUtils.hasText(builder.getCacheResolver())) {
// One of these is set so we should not inherit anything
}
else if (StringUtils.hasText(this.cacheResolver)) {
builder.setCacheResolver(this.cacheResolver);
}
else if (StringUtils.hasText(this.cacheManager)) {
builder.setCacheManager(this.cacheManager);
}
}
@Test
public void multipleAnnotation() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multiple", 2);
Iterator<CacheOperation> it = ops.iterator();
assertTrue(it.next() instanceof CacheableOperation);
assertTrue(it.next() instanceof CacheEvictOperation);
}
@Test
public void caching() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "caching", 2);
Iterator<CacheOperation> it = ops.iterator();
assertTrue(it.next() instanceof CacheableOperation);
assertTrue(it.next() instanceof CacheEvictOperation);
}
@Test
public void singleComposedAnnotation() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "singleComposed", 2);
Iterator<CacheOperation> it = ops.iterator();
CacheOperation cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("directly declared")));
assertThat(cacheOperation.getKey(), equalTo(""));
cacheOperation = it.next();
assertThat(cacheOperation, instanceOf(CacheableOperation.class));
assertThat(cacheOperation.getCacheNames(), equalTo(Collections.singleton("composedCache")));
assertThat(cacheOperation.getKey(), equalTo("composedKey"));
}
<T extends CacheOperation.Builder> T merge(Element element, ReaderContext readerCtx, T builder) {
String cache = element.getAttribute("cache");
// sanity check
String[] localCaches = this.caches;
if (StringUtils.hasText(cache)) {
localCaches = StringUtils.commaDelimitedListToStringArray(cache.trim());
}
else {
if (this.caches == null) {
readerCtx.error("No cache specified for " + element.getNodeName(), element);
}
}
builder.setCacheNames(localCaches);
builder.setKey(getAttributeValue(element, "key", this.key));
builder.setKeyGenerator(getAttributeValue(element, "key-generator", this.keyGenerator));
builder.setCacheManager(getAttributeValue(element, "cache-manager", this.cacheManager));
builder.setCondition(getAttributeValue(element, "condition", this.condition));
if (StringUtils.hasText(builder.getKey()) && StringUtils.hasText(builder.getKeyGenerator())) {
throw new IllegalStateException("Invalid cache advice configuration on '"
+ element.toString() + "'. Both 'key' and 'keyGenerator' attributes have been set. " +
"These attributes are mutually exclusive: either set the SpEL expression used to" +
"compute the key at runtime or set the name of the KeyGenerator bean to use.");
}
return builder;
}
protected Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
Collection<CacheOperation> ops = null;
Collection<Cacheable> cacheables = getAnnotations(ae, Cacheable.class);
if (cacheables != null) {
ops = lazyInit(ops);
for (Cacheable cacheable : cacheables) {
ops.add(parseCacheableAnnotation(ae, cachingConfig, cacheable));
}
}
Collection<CacheEvict> evicts = getAnnotations(ae, CacheEvict.class);
if (evicts != null) {
ops = lazyInit(ops);
for (CacheEvict evict : evicts) {
ops.add(parseEvictAnnotation(ae, cachingConfig, evict));
}
}
Collection<CachePut> puts = getAnnotations(ae, CachePut.class);
if (puts != null) {
ops = lazyInit(ops);
for (CachePut put : puts) {
ops.add(parsePutAnnotation(ae, cachingConfig, put));
}
}
Collection<Caching> cachings = getAnnotations(ae, Caching.class);
if (cachings != null) {
ops = lazyInit(ops);
for (Caching caching : cachings) {
ops.addAll(parseCachingAnnotation(ae, cachingConfig, caching));
}
}
return ops;
}
@Test
public void multipleAnnotation() throws Exception {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multiple", 2);
Iterator<CacheOperation> it = ops.iterator();
assertTrue(it.next() instanceof CacheableOperation);
assertTrue(it.next() instanceof CacheEvictOperation);
}
@Test
public void caching() throws Exception {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "caching", 2);
Iterator<CacheOperation> it = ops.iterator();
assertTrue(it.next() instanceof CacheableOperation);
assertTrue(it.next() instanceof CacheEvictOperation);
}
@Test
public void validateNoCacheIsValid() {
// Valid as a CacheResolver might return the cache names to use with other info
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "noCacheNameSpecified");
CacheOperation cacheOperation = ops.iterator().next();
assertNotNull("cache names set must not be null", cacheOperation.getCacheNames());
assertEquals("no cache names specified", 0, cacheOperation.getCacheNames().size());
}
@Test
public void cacheAnnotationOverride() {
Collection<CacheOperation> ops = getOps(InterfaceCacheConfig.class, "interfaceCacheableOverride");
assertSame(1, ops.size());
CacheOperation cacheOperation = ops.iterator().next();
assertTrue(cacheOperation instanceof CacheableOperation);
}
/**
* Determine the cache operation(s) for the given {@link CacheOperationProvider}.
* <p>This implementation delegates to configured
* {@link CacheAnnotationParser}s for parsing known annotations into
* Spring's metadata attribute class.
* <p>Can be overridden to support custom annotations that carry
* caching metadata.
* @param provider the cache operation provider to use
* @return the configured caching operations, or {@code null} if none found
*/
protected Collection<CacheOperation> determineCacheOperations(CacheOperationProvider provider) {
Collection<CacheOperation> ops = null;
for (CacheAnnotationParser annotationParser : this.annotationParsers) {
Collection<CacheOperation> annOps = provider.getCacheOperations(annotationParser);
if (annOps != null) {
if (ops == null) {
ops = new ArrayList<CacheOperation>();
}
ops.addAll(annOps);
}
}
return ops;
}
private Collection<CacheOperation> getOps(Class<?> target, String name) {
try {
Method method = target.getMethod(name);
return this.source.getCacheOperations(method, target);
}
catch (NoSuchMethodException ex) {
throw new IllegalStateException(ex);
}
}
private void assertSharedConfig(CacheOperation actual, String keyGenerator, String cacheManager,
String cacheResolver, String... cacheNames) {
assertEquals("Wrong key manager", keyGenerator, actual.getKeyGenerator());
assertEquals("Wrong cache manager", cacheManager, actual.getCacheManager());
assertEquals("Wrong cache resolver", cacheResolver, actual.getCacheResolver());
assertEquals("Wrong number of cache names", cacheNames.length, actual.getCacheNames().size());
Arrays.stream(cacheNames).forEach(cacheName ->
assertTrue("Cache '" + cacheName + "' not found in " + actual.getCacheNames(),
actual.getCacheNames().contains(cacheName)));
}
@Nullable
private Collection<CacheOperation> parseCacheAnnotations(DefaultCacheConfig cachingConfig, AnnotatedElement ae) {
Collection<CacheOperation> ops = parseCacheAnnotations(cachingConfig, ae, false);
if (ops != null && ops.size() > 1) {
// More than one operation found -> local declarations override interface-declared ones...
Collection<CacheOperation> localOps = parseCacheAnnotations(cachingConfig, ae, true);
if (localOps != null) {
return localOps;
}
}
return ops;
}
/**
* Apply the defaults to the specified {@link CacheOperation.Builder}.
* @param builder the operation builder to update
*/
public void applyDefault(CacheOperation.Builder builder) {
if (!this.initialized) {
CacheConfig annotation = AnnotatedElementUtils.findMergedAnnotation(this.target, CacheConfig.class);
if (annotation != null) {
this.cacheNames = annotation.cacheNames();
this.keyGenerator = annotation.keyGenerator();
this.cacheManager = annotation.cacheManager();
this.cacheResolver = annotation.cacheResolver();
}
this.initialized = true;
}
if (builder.getCacheNames().isEmpty() && this.cacheNames != null) {
builder.setCacheNames(this.cacheNames);
}
if (!StringUtils.hasText(builder.getKey()) && !StringUtils.hasText(builder.getKeyGenerator()) &&
StringUtils.hasText(this.keyGenerator)) {
builder.setKeyGenerator(this.keyGenerator);
}
if (StringUtils.hasText(builder.getCacheManager()) || StringUtils.hasText(builder.getCacheResolver())) {
// One of these is set so we should not inherit anything
}
else if (StringUtils.hasText(this.cacheResolver)) {
builder.setCacheResolver(this.cacheResolver);
}
else if (StringUtils.hasText(this.cacheManager)) {
builder.setCacheManager(this.cacheManager);
}
}
@Test
public void multipleAnnotation() {
Collection<CacheOperation> ops = getOps(AnnotatedClass.class, "multiple", 2);
Iterator<CacheOperation> it = ops.iterator();
assertTrue(it.next() instanceof CacheableOperation);
assertTrue(it.next() instanceof CacheEvictOperation);
}