提交 faef363e 编写于 作者: J Juergen Hoeller

Evaluate @Cacheable(condition) once per method invocation only

Issue: SPR-17024
上级 93d91219
......@@ -693,6 +693,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
private final Collection<String> cacheNames;
@Nullable
private Boolean conditionPassing;
public CacheOperationContext(CacheOperationMetadata metadata, Object[] args, Object target) {
this.metadata = metadata;
this.args = extractArgs(metadata.method, args);
......@@ -733,12 +736,17 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker
}
protected boolean isConditionPassing(@Nullable Object result) {
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
return evaluator.condition(this.metadata.operation.getCondition(),
this.metadata.methodKey, evaluationContext);
if (this.conditionPassing == null) {
if (StringUtils.hasText(this.metadata.operation.getCondition())) {
EvaluationContext evaluationContext = createEvaluationContext(result);
this.conditionPassing = evaluator.condition(this.metadata.operation.getCondition(),
this.metadata.methodKey, evaluationContext);
}
else {
this.conditionPassing = true;
}
}
return true;
return this.conditionPassing;
}
protected boolean canPutToCache(@Nullable Object value) {
......
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2018 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.
......@@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicLong;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.CacheTestUtils;
......@@ -33,7 +34,10 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.mock.env.MockEnvironment;
import static org.junit.Assert.*;
import static org.springframework.cache.CacheTestUtils.*;
/**
......@@ -45,6 +49,7 @@ public class EnableCachingIntegrationTests {
private ConfigurableApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
......@@ -52,6 +57,7 @@ public class EnableCachingIntegrationTests {
}
}
@Test
public void fooServiceWithInterface() {
this.context = new AnnotationConfigApplicationContext(FooConfig.class);
......@@ -77,22 +83,48 @@ public class EnableCachingIntegrationTests {
}
@Test
public void beanCondition() {
public void beanConditionOff() {
this.context = new AnnotationConfigApplicationContext(BeanConditionConfig.class);
Cache cache = getCache();
FooService service = this.context.getBean(FooService.class);
Cache cache = getCache();
Object key = new Object();
service.getWithCondition(key);
assertCacheMiss(key, cache);
service.getWithCondition(key);
assertCacheMiss(key, cache);
assertEquals(2, this.context.getBean(BeanConditionConfig.Bar.class).count);
}
@Test
public void beanConditionOn() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.setEnvironment(new MockEnvironment().withProperty("bar.enabled", "true"));
ctx.register(BeanConditionConfig.class);
ctx.refresh();
this.context = ctx;
FooService service = this.context.getBean(FooService.class);
Cache cache = getCache();
Object key = new Object();
Object value = service.getWithCondition(key);
assertCacheHit(key, value, cache);
value = service.getWithCondition(key);
assertCacheHit(key, value, cache);
assertEquals(2, this.context.getBean(BeanConditionConfig.Bar.class).count);
}
private Cache getCache() {
return this.context.getBean(CacheManager.class).getCache("testCache");
}
@Configuration
static class SharedConfig extends CachingConfigurerSupport {
@Override
@Bean
public CacheManager cacheManager() {
......@@ -100,34 +132,42 @@ public class EnableCachingIntegrationTests {
}
}
@Configuration
@Import(SharedConfig.class)
@EnableCaching
static class FooConfig {
@Bean
public FooService fooService() {
return new FooServiceImpl();
}
}
@Configuration
@Import(SharedConfig.class)
@EnableCaching(proxyTargetClass = true)
static class FooConfigCglib {
@Bean
public FooService fooService() {
return new FooServiceImpl();
}
}
private interface FooService {
Object getSimple(Object key);
Object getWithCondition(Object key);
}
@CacheConfig(cacheNames = "testCache")
private static class FooServiceImpl implements FooService {
private final AtomicLong counter = new AtomicLong();
@Override
......@@ -143,17 +183,25 @@ public class EnableCachingIntegrationTests {
}
}
@Configuration
@Import(FooConfig.class)
@EnableCaching
static class BeanConditionConfig {
@Autowired
Environment env;
@Bean
public Bar bar() {
return new Bar(false);
return new Bar(Boolean.valueOf(env.getProperty("bar.enabled")));
}
static class Bar {
public int count;
private final boolean enabled;
public Bar(boolean enabled) {
......@@ -161,6 +209,7 @@ public class EnableCachingIntegrationTests {
}
public boolean isEnabled() {
this.count++;
return this.enabled;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册