問題現象
我們從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物件被建立出來之後,其內部的值是可以通過某些內部方法進行改變的。