EhCache модификация кешированного объекта
Я должен реализовать кэширование с EhCache. Основным требованием является то, что я должен хранить этот кэшированный объект в течение фиксированного интервала (сейчас 1 час в коде ниже). Итак, я реализовал код, как показано ниже:
Пример объекта домена:
import lombok.*;
@Getter
@Setter
@ToString
@AllArgsConstructor
public class City implements Serializable {
public String name;
public String country;
public int population;
}
Класс менеджера кэша:
import net.sf.ehcache.*;
public class JsonObjCacheManager {
private static final Logger logger = LoggerFactory.getLogger(JsonObjCacheManager.class);
private CacheManager manager;
private Cache objectCache;
public JsonObjCacheManager(){
manager = CacheManager.create();
objectCache = manager.getCache("jsonDocCache");
if( objectCache == null){
objectCache = new Cache(
new CacheConfiguration("jsonDocCache", 1000)
.memoryStoreEvictionPolicy(MemoryStoreEvictionPolicy.LRU)
.eternal(false)
.timeToLiveSeconds(60 * 60)
.timeToIdleSeconds(0)
.diskExpiryThreadIntervalSeconds(0)
.persistence(new PersistenceConfiguration().strategy(PersistenceConfiguration.Strategy.LOCALTEMPSWAP)));
objectCache.disableDynamicFeatures();
manager.addCache(objectCache);
}
}
public List<String> getKeys() { return objectCache.getKeys();}
public void clearCache(){
manager.removeAllCaches();
}
public void putInCache(String key, Object value){
try{
objectCache.put(new Element(key, value));
}catch (CacheException e){
logger.error(String.format( "Problem occurred while putting data into cache: %s", e.getMessage()));
}
}
public Object retrieveFromCache(String key){
try {
Element element = objectCache.get(key);
if(element != null)
return element.getObjectValue();
}catch (CacheException ce){
logger.error(String.format("Problem occurred while trying to retrieveSpecific from cache: %s", ce.getMessage()));
}
return null;
}
}
Он кэширует и получает значения очень правильно. Но мое требование заключается в том, что я должен изменить объект, который я извлекаю из кэша для данного ключа. Что я получаю, так это то, что если я изменяю объект, который я извлек из кеша, то кешированный объект для этого ключа также изменяется.
Ниже приведен пример:
public class Application {
public static void main(String[] args) {
JsonObjCacheManager manager = new JsonObjCacheManager();
final City city1 = new City("ATL","USA",12100);
final City city2 = new City("FL","USA",12000);
manager.putInCache(city1.getName(), city1);
manager.putInCache(city2.getName(), city2);
System.out.println(manager.getKeys());
for(String key: manager.getKeys()){
System.out.println(key + ": "+ manager.retrieveFromCache(key));
}
City cityFromCache = (City) manager.retrieveFromCache(city1.getName());
cityFromCache.setName("KTM");
cityFromCache.setCountry("NPL");
System.out.println(manager.getKeys());
for(String key: manager.getKeys()){
System.out.println(key + ": "+ manager.retrieveFromCache(key));
}
}
}
Вывод, который я получаю:
[ATL, FL]
ATL: City(name=ATL, country=USA, population=12100)
FL: City(name=FL, country=USA, population=12000)
[ATL, FL]
ATL: City(name=KTM, country=NPL, population=12100)
FL: City(name=FL, country=USA, population=12000)
Это означает, что всякий раз, когда я получаю и изменяю объект для данного ключа, он также отражается в кэшированном значении.
Каково мое требование, кешированный объект для данного ключа не должен изменяться. Есть ли способ добиться этого? Или это не правильный способ реализации EhCache? Или мне не хватает какого-то фундаментального принципа?
Я использую EhCache V2.10.3
Спасибо!
1 ответ
Когда вы используете кеш, который хранит свои данные в куче и с прямыми ссылками на объекты, вам необходимо скопировать объект перед его использованием.
Как правило, рекомендуется не изменять значение после передачи ссылки на объект в кэш (или кого-либо еще вне вашего контроля).
Некоторые кэши имеют механизм копирования для защиты кэшированных значений от модификации. Например, в EHCache3 вы можете добавить копиры, см. Сериализаторы и копиры.
В качестве альтернативы, измените свой дизайн: если вам нужно изменить значение, возможно, вы можете разделить значения на два объекта, один из которых является кэшем, другой содержит данные, которые должны быть изменены, и создайте последний, содержащий первый.