java - spring @Cacheable 继承

标签 java spring spring-cache

如何进行以下工作?

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, 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>

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

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

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

谢谢。

关于java - spring @Cacheable 继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29501873/

相关文章:

java - 在 Java 中,有时方法参数的行为类似于通过引用传递,尽管事实并非如此。他们通过什么方法?

java - jacoco 代码覆盖率报告生成器显示错误 : "Classes in bundle ' Code Coverage Report' do no match with execution data"

java.lang.NoClassDefFoundError : org/springframework/web/client/ResponseErrorHandler 错误

spring - 是否有 Spring-boot 和 Spring-cloud 的兼容性矩阵?

java.lang.NoClassDefFoundError : net/sf/ehcache/concurrent/ReadWriteLockSync

java - java中 "22:40:29.668 EET Sun Jan 02 2011"的日期格式是什么?

java - 如何在Gwt的PopupPanel中添加取消按钮

spring - 这很可能在 Tomcat 中造成内存泄漏吗?

spring-cache - spring 缓存确实可以使用嵌套方法

java - 如何在 Spring Boot 中缓存 CompletableFuture 的值