【发布时间】:2015-06-16 05:51:22
【问题描述】:
我的任务是为我们的一项服务使用 SpringCache,以减少数据库查找的次数。在测试实现时,我注意到一些可缓存的操作通过日志语句多次调用。调查显示,如果在可缓存方法中调用可缓存操作,则嵌套操作根本不会被缓存。因此,稍后调用嵌套操作会导致进一步查找。
描述问题的简单单元测试如下:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringCacheTest.Config.class} )
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
public class SpringCacheTest {
private final static String CACHE_NAME = "testCache";
private final static Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final static AtomicInteger methodInvocations = new AtomicInteger(0);
public interface ICacheableService {
String methodA(int length);
String methodB(String name);
}
@Resource
private ICacheableService cache;
@Test
public void testNestedCaching() {
String name = "test";
cache.methodB(name);
assertThat(methodInvocations.get(), is(equalTo(2)));
cache.methodA(name.length());
// should only be 2 as methodA for this length was already invoked before
assertThat(methodInvocations.get(), is(equalTo(3)));
}
@Configuration
public static class Config {
@Bean
public CacheManager getCacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache(CACHE_NAME)));
return cacheManager;
}
@Bean
public ICacheableService getMockedEntityService() {
return new ICacheableService() {
private final Random random = new Random();
@Cacheable(value = CACHE_NAME, key = "#root.methodName.concat('_').concat(#p0)")
public String methodA(int length) {
methodInvocations.incrementAndGet();
LOG.debug("Invoking methodA");
char[] chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray();
StringBuilder sb = new StringBuilder();
for (int i=0; i<length; i++) {
sb.append(chars[random.nextInt(chars.length)]);
}
String result = sb.toString();
LOG.debug("Returning {} for length: {}", result, length);
return result;
}
@Cacheable(value = CACHE_NAME, key = "#root.methodName.concat('_').concat(#p0)")
public String methodB(String name) {
methodInvocations.incrementAndGet();
LOG.debug("Invoking methodB");
String rand = methodA(name.length());
String result = name+"_"+rand;
LOG.debug("Returning {} for name: {}", result, name);
return result;
}
};
}
}
}
这两种方法的实际工作对测试用例本身并不重要,因为只需要测试缓存。
我以某种方式理解嵌套操作的结果未缓存的原因,但我想知道是否有可用的配置,我还没有弄清楚,以启用对嵌套可缓存操作的返回值的缓存。
我知道通过重构并提供嵌套操作的返回值作为外部操作的参数是可行的,但这可能涉及更改许多操作(以及对它们进行单元测试)配置或其他在我们的具体案例中,解决方法(如果可用)会更好。
【问题讨论】: