diff --git a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java index bef068079e6..cd6c84ab9f5 100644 --- a/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java +++ b/spring-context/src/main/java/org/springframework/cache/interceptor/CacheAspectSupport.java @@ -693,6 +693,9 @@ public abstract class CacheAspectSupport extends AbstractCacheInvoker private final Collection 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) { diff --git a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java index d95c70d1002..27f950df6eb 100644 --- a/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/config/EnableCachingIntegrationTests.java @@ -1,5 +1,5 @@ /* - * 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; } }