spring@可缓存继承



如何实现以下功能?

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来说,同样的方法并没有失败。

也许您需要检查应用程序域对象上的"equals"(和"hashCode")实现;确保它们得到了正确的实现和良好的格式(请参阅Effective Java,第2版,第8项-重写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>

请记住,一些缓存实现(例如Pivotal GemFire)可以选择"读取时复制"或序列化存储在缓存中的值。前者适用于事务等问题,而后者始终适用于缓存,缓存也是分布式数据网格,其中(缓存的)数据在节点集群中进行分区(分片)。

可能有许多影响结果的因素(即equals方法构造、读取属性、序列化)需要注意,因此请查看特定缓存实现的设置。

如果你对我的例子有任何问题,或者我们的问题仍然存在,请随时跟进。也许您可以了解应用程序域对象类型和正在使用的缓存实现/配置。

谢谢。

最新更新