如何进行以下工作?
public abstract class MyAbstractOne {
@Cacheable(value="myCache")
public MyObject getObject() {
//some code
return object;
}
}
子类
public class MySubClass extends MyAbstractOne {
@Cacheable(value="myCache")
public MyOtherObject getObjectConcrete() {
//some code
return object;
}
}
以及这些对象的用户
//from autowired instance
@Autowired MySubClass subObject;
然后在某处
//first call - may not retrieve cached objects
obj1 = subObject.getMyObject();
//second call - SHOULD retrieve a cached objects
obj2 = subObject.getMyObject();
为什么会失败
assertTrue(obj1.equals(obj2));
但getMyObjectConcrete的相同内容不会失败。
答案 0 :(得分:3)
也许您需要检查应用程序域对象上的“equals”(和“hashCode”)实现;确保它们得到妥善实施并形成良好(见Effective Java, 2nd Edition, Item 8 - Obey the the general contract when overriding equals)。
我能够得到一个类似于上面代码片段的小型简单应用程序......
package org.spring.cache;
import static org.junit.Assert.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ObjectUtils;
/**
* The CachingWithConcurrentMapTest class is a test suite of test cases testing the contract and functionality
* of @Cacheable inheritance.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.cache.annotation.Cacheable
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @since 1.0.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class CachingWithConcurrentMapTest {
@Autowired
private FactorialComputeService computeService;
@Test
public void testCachedObject() {
ValueHolder<Long> twoSquared = computeService.squared(2l);
ValueHolder<Long> twoSquaredAgain = computeService.squared(2l);
assertEquals(twoSquared, twoSquaredAgain);
assertSame(twoSquared, twoSquaredAgain);
ValueHolder<Long> fourFactorial = computeService.factorial(4l);
ValueHolder<Long> fourFactorialAgain = computeService.factorial(4l);
assertEquals(fourFactorial, fourFactorialAgain);
assertSame(fourFactorial, fourFactorialAgain);
assertNotSame(twoSquared, fourFactorial);
ValueHolder<Long> eightSquared = computeService.squared(8l);
ValueHolder<Long> eightSquaredAgain = computeService.squared(8l);
assertEquals(eightSquared, eightSquaredAgain);
assertSame(eightSquared, eightSquaredAgain);
assertNotSame(twoSquared, eightSquared);
assertNotSame(fourFactorial, eightSquared);
}
@Service
public static class SquaredComputeService {
@Cacheable("Computations")
public ValueHolder<Long> squared(Long value) {
return new ValueHolder<>(value * value);
}
}
@Service
public static class FactorialComputeService extends SquaredComputeService {
@Cacheable("Computations")
public ValueHolder<Long> factorial(Long value) {
return new ValueHolder<>(computeFactorial(value));
}
protected long computeFactorial(long value) {
long result = value;
while (--value > 0) {
result *= value;
}
return result;
}
}
public static class ValueHolder<T> {
private T value;
public ValueHolder() {
this(null);
}
public ValueHolder(final T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void setValue(final T value) {
this.value = value;
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ValueHolder)) {
return false;
}
ValueHolder that = (ValueHolder) obj;
return ObjectUtils.nullSafeEquals(this.getValue(), that.getValue());
}
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getValue());
return hashValue;
}
@Override
public String toString() {
return String.format("{ @type = %1$s, value = %2$s }", getClass().getName(), getValue());
}
}
}
相应的Spring配置......
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
">
<context:annotation-config/>
<cache:annotation-driven/>
<bean id="cacheManager" class="org.springframework.cache.concurrent.ConcurrentMapCacheManager"/>
<bean id="service" class="org.spring.cache.CachingWithConcurrentMapTest.FactorialComputeService"/>
</beans>
请记住,某些Cache实现(例如Pivotal GemFire)可以选择“copy-on-read”或序列化存储在Cache中的值。前者对于像交易这样的问题很有用,而后者总是适用于也是分布数据网格的缓存,其中(缓存)数据在节点集群中被分区(分片)。
可能有许多因素会影响您的结果(即等于方法构造,读取属性,序列化),因此请查看特定缓存实现的设置。
如果您的示例有任何问题,或者我们的问题仍然存在,请随时跟进。也许您可以了解您的应用程序域对象类型和正在使用的缓存实现/配置。
感谢。