类org.springframework.cache.interceptor.CacheOperation源码实例Demo

下面列出了怎么用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"));
}
 
源代码5 项目: lams   文件: SpringCacheAnnotationParser.java
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"));
}
 
源代码19 项目: lams   文件: CacheAdviceParser.java
<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);
}
 
 类方法
 同包方法