修改Ehcache快取中取到的值,快取中的值也被修改了
阿新 • • 發佈:2022-03-06
修改Ehcache快取中取到的值,快取中的值也被修改了
問題現象
我們從Ehcache中取出快取的物件,之後將物件中的屬性進行了修改使用。等再次從快取中拿到物件後,發現物件的值變成了上一次呼叫修改後的物件了。
原因
Ehcache中快取的是原物件的引用,所以引用的內容被修改後cache內部的值也會被修改。
解決方案
使用Ehcache的copyStrategy
Ehcache提供了copyOnRead="true" copyOnWrite="true"的配置屬性。
作用是在讀取或寫入資料時,不使用原始資料,而是使用拷貝資料。
但是在使用該配置的時候,還要提供copyStrategy class屬性,提供Copy策略。
<cache name="bannerCache" eternal="false" maxElementsInMemory="50" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="300" timeToLiveSeconds="300" memoryStoreEvictionPolicy="LFU" copyOnRead="true" copyOnWrite="true"> <copyStrategy class="com.xxx.EhcacheCopyStrategy" /> </cache>
copy策略類
public class EhcacheCopyStrategy implements ReadWriteCopyStrategy<Element> { @Override public Element copyForWrite(Element value) { if(value != null){ Object temp=(Serializable)value.getObjectValue(); try { return new Element(value.getObjectKey(),deepCopy(temp)); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return value; } @Override public Element copyForRead(Element storedValue) { if(storedValue != null){ Object temp=(Serializable)storedValue.getObjectValue(); try { return new Element(storedValue.getObjectKey(),deepCopy(temp)); } catch (ClassNotFoundException | IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return storedValue; } private Object deepCopy(Object src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); return in.readObject(); } }
使用immutable物件
將我們的實體類設計成immutable的,如果需要修改就建立一個新的物件。
如何構建一個immutable物件
- 確保fields中的成員都被private final修飾;private保證內部成員不會被外部直接訪問,final保證成員在初始化後不會被assigned。
- 不提供改變成員的方法,例如setXxx。
- 使用final修飾自定義的類,確保類中的方法不會被重寫。
- 如果類中的某個成員是mutable型別的,那麼在初始化該成員或者企圖用get方法從外部對其觀察時,應該使用深度拷貝,確保immutable。
String類
String類是java中典型的immutable資料型別,一個String物件一旦唄new出來後,就不能被修改,否則就會報assigned錯誤。
StringBuilder類的物件是mutable的資料型別,當一個StringBuilder物件被創建出來之後,其內部的值是可以通過某些內部方法進行改變的。