zoukankan      html  css  js  c++  java
  • ehcache2拾遗之copyOnRead,copyOnWrite

    问题描述

    缓存在提升应用性能,提高访问效率上都是至关重要的一步。ehcache也是广为使用的缓存之一。但是如果将一个可变的对象(如普通的POJO/List/Map等)存入缓存中,会导致怎样潜在的问题。下面来看一个例子

        //首先创建一个简单的POJO
        public class Student {
            private String name;
            public Student(String name){
                this.setName(name);
            }
            public String getName() {
                return name;
            }
            public void setName(String name) {
                this.name = name;
            }
        }
    

    之后创建一个POJO并使用ehcache来进行缓存

        @Test
        public void copyOnRead(){
            CacheManager cache=CacheManager.create("cache.xml");      //读取cache配置文件,如果不配置ehcache有默认的failsafe配置
            Ehcache copyCache=cache.addCacheIfAbsent("copyCache");    //读取名为copyCache的cache,如果没有则创建
            Student stu=new Student("张三");                          //创建一个简单的POJO
            Element el=new Element(1,stu);                            //将对象放入Element对象
            copyCache.put(el);                                        //存入缓存
            stu.setName("李四");                                      //之后改变POJO的内容
            Student cachedStu=(Student) copyCache.get(1).getObjectValue();//从缓存中取出对象
            System.out.println("cache中取出的对象的名字:"+cachedStu.getName());
            System.out.println("cache中取出的对象和源对象相等:"+(copyCache.get(1)==el));
            System.out.println("两次cache中取出的对象相等"+(copyCache.get(1)==copyCache.get(1)));
        }
    

    以上代码的输出结果是

        cache中取出的对象的名字:李四
        cache中取出的对象和源对象相等:true
        两次cache中取出的对象相等true
    

    可以看到缓存中的对象在外部对象被修改时也被修改了(这里只考虑内存缓存,不考虑序列化到磁盘)。

    原因分析

    这是由于ehcache中存放的Element对象是直接保存了原对象的引用,所以引用的内容被修改之后cache内部的值也会被修改。

    解决办法

    首先这种现象并非一定是有问题的,有的应用场景就是希望保存对象的引用,但是这会导致部分误操作,如果不小心无意修改了对象的值就会导致数据不准确。
    知道了原因那么也就好解决问题了:

    使用immutable对象

    将POJO设计成immutable的,如果需要修改就新建一个新的对象,这个也是fp所推崇的方案。

    使用ehcache的copyStrategy

    如果是遗留项目的话上面的方法可能就不适合了,好在在ehcache中已经实现了接口可以拦截read、write等操作,并对存入、读取的Element对象进行修改

        public class MyCopyStrategy implements ReadWriteCopyStrategy<Element> {
            //当write缓存的时候会调用这个方法
            public Element copyForWrite(Element value, ClassLoader loader) {
                Student temp=(Student) value.getObjectValue();
                return new Element(value.getObjectKey(),new Student(temp.getName()+"_w"));
            }
            //当read缓存的时候会调用这个方法
            public Element copyForRead(Element storedValue, ClassLoader loader) {
                Student temp=(Student) storedValue.getObjectValue();
                return new Element(storedValue.getObjectKey(),new Student(temp.getName()+"_r"));
            }
        }
    

    如上只要实现了ReadWriteCopyStrategy就可以修改存入、读取的对象。这里在读取时我再名字后加了一个r,在存入时名字后加了一个w
    还需要注入到cache中

        //配置文件
        <cache name="copyCache" maxEntriesLocalHeap="1" eternal="false"
            timeToIdleSeconds="1" timeToLiveSeconds="1" copyOnRead="true" copyOnWrite="true">
            <copyStrategy class="echach2.MyCopyStrategy" />
        </cache>
    

    使用copyStrategy将strategy配置到cache中,再运行上面的代码

        张三_w_r
        cache中取出的对象和源对象相等:false
        两次cache中取出的对象相等false
    

    这里可以看到存在的cache中的对象和原对象并不一样,两次cache取出来的对象也不同。

    小结

    ehcache的copyStratgy可以有效防止引用对象在外部被误改,但是这每次都复制一个对象,对性能还是有一定的影响的,所以可能的话还是尽量使用immutable的对象。

  • 相关阅读:
    HTTP断点续传 规格严格
    Java Shutdown 规格严格
    linux 命令源码 规格严格
    JTable调整列宽 规格严格
    linux 多CPU 规格严格
    Hello can not find git path 规格严格
    Kill 规格严格
    拜拜牛人 规格严格
    Swing 规格严格
    Debugging hangs in JVM (on AIX but methodology applicable to other platforms) 规格严格
  • 原文地址:https://www.cnblogs.com/resentment/p/5789644.html
Copyright © 2011-2022 走看看