2

我正在使用 ehcache 作为缓存实现来解决 spring 3.1 注释缓存。

像这样返回值的方法

@Cacheable("cache")
public MyObject getObj(Object param);

我第一次得到了一个 myobject 返回值,它是可编辑的。ehcache 可以通过设置“copyOnRead”或“copyOnWrite”来做一些事情。它将在读/写时强制序列化对象。但是第一次spring不会从缓存中获取值,它总是通过方法本身返回。

有没有办法获得一个只读的返回值?

4

3 回答 3

3

您可以编写自己的方面,始终创建返回值的副本,这将使您独立于某些 Ehcache 设置。

起初,像@CopyReturnValue这样的标记注释可以很好地表达切入点:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CopyReturnValue {
}

现在,切面可以将此注解用于切入点表达式:

@Aspect
@Component
public class CopyReturnValueAspect {
    @Around("@annotation(CopyReturnValue)")
    public Object doCopyReturnValue(ProceedingJoinPoint pjp) throws Throwable {
        Object retVal = pjp.proceed();
        Object copy = BeanUtils.cloneBean(retVal); // create a copy in some way
        return copy;
    }
}

最后,将注释添加到您的方法中:

@CopyReturnValue
@Cacheable("cache")
public MyObject getObj(Object param);

对于CopyReturnValueAspectBeanUtils用来创建返回值的副本 - 仅作为示例。有关该主题的更多信息,您可能需要查看如何将属性从一个 Java bean 复制到另一个?

哦,别忘了在 Spring 配置中启用 @AspectJ 支持(如果您还没有的话):

<aop:aspectj-autoproxy />
于 2012-06-12T22:15:53.970 回答
1

我对弹簧缓存有同样的问题。我不想从缓存中接收相同的 java 对象。

就我而言,我想缓存具有许多字段等的大型 Java 对象。所以用深拷贝来拷贝所有的数据类是很痛苦的。我阅读了有关使用序列化复制 java 对象的文章。

http://www.javaworld.com/article/2077578/learn-java/java-tip-76--an-alternative-to-the-deep-copy-technique.html

这让我想到了只缓存序列化数据的想法。每次从缓存中读取对象时,都会对其进行反序列化。

对于序列化,我使用了 apache commons helper 方法

@Override
public SerializedQuestions readUserQuestion(UID questionId, Locale locale) {
 byte[] serializedData = readCachedUserQuestion(questionId, locale);
 Object deserializedobject = org.apache.commons.lang.SerializationUtils.deserialize(serializedData);
 return (SerializedQuestions) deserialize;
}

@Override
@Cacheable(value = SpringCacheKeys.USER_QUESTION_CACHE)
  public byte[] readCachedUserQuestion(UID questionId, Locale locale) {

  //read object from db
  SerializedQuestions questions = new SerializedQuestions()

  return org.apache.commons.lang.SerializationUtils.serialize(questions);
}

如果对readCachedUserQuestion的调用可能在同一个类中,则取决于 spring 配置。默认情况下,仅缓存对方法的外部调用。

于 2017-05-02T14:28:13.127 回答
0

我找到了一个对我有用的肮脏的解决方案。通过创建另一个类,它包含与返回的对象相同的属性,然后我使用 ModelMapper 将返回的对象映射到我的新对象。例如我有一个 MyObject 类:

    public class MyObject {
     private Long id;
     private Long label;

    //getters and setters
    }

新的 Created 类:

public class MyObjectCopy {
    private Long id;
    private Long label;

    //getters and setters
}

以及一个返回 MyObject 的可缓存方法:

 @Cacheable("cache")
public MyObject getMyObject();

并防止缓存被修改:我必须将该对象映射到我的 classCopy 然后我处理它:

MyObjectCopy myObjectCopy = modelMapper.map(myobject, MyObjectCopy.class);

不要忘记为嵌套对象创建一个复制类;

于 2020-07-02T15:59:03.707 回答