Ehcache中能夠使用Cache來保存須要緩存的對像,但須要把對象封裝在Element的實例裏。
java
往Cache中添加對像: 緩存
CacheManager manager = CacheManager.newInstance("src/config/cache.xml"); manager.addCache("testCache"); Cache cache = singletonManager.getCache("testCache"); Element element = new Element("key", "value"); cache.put(element);
相應源碼:安全
/** * Put an element in the cache. * <p/> * Resets the access statistics on the element, which would be the case if it has previously been * gotten from a cache, and is now being put back. * <p/> * Also notifies the CacheEventListener that: * <ul> * <li>the element was put, but only if the Element was actually put. * <li>if the element exists in the cache, that an update has occurred, even if the element would be expired * if it was requested * </ul> * <p/> * Caches which use synchronous replication can throw RemoteCacheException here if the replication to the cluster fails. * This exception should be caught in those circumstances. * * @param element A cache Element. If Serializable it can fully participate in replication and the DiskStore. If it is * <code>null</code> or the key is <code>null</code>, it is ignored as a NOOP. * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} * @throws CacheException */ public final void put(Element element) throws IllegalArgumentException, IllegalStateException, CacheException { put(element, false); }
Element UML類圖:app
構造一個Element對象很簡單,Cache沒有什麼複雜的操做。但看似簡單的put操做,它的實現是還有點複雜。maven
Step 1: 開發者調用Cache的put方法。ui
cache.put(element);
Step 2: 對應的源碼this
public final void put(Element element) throws IllegalArgumentException, IllegalStateException, CacheException { put(element, false); }
Step 3: 默認狀況下doNotNotifyCacheReplicators的值是false.暫時先不討論集羣。spa
private void putAll(Collection<Element> elements, boolean doNotNotifyCacheReplicators) throws IllegalArgumentException,線程
IllegalStateException, CacheException {debug
putAllInternal(elements, doNotNotifyCacheReplicators);
}
Step 4: 具體實現細節。 能夠大概看一下,今天咱們主要分析一下 putObserver這個變量的做用。
private void putInternal(Element element, boolean doNotNotifyCacheReplicators, boolean useCacheWriter) { putObserver.begin(); if (useCacheWriter) { initialiseCacheWriterManager(true); } checkStatus(); if (disabled) { putObserver.end(PutOutcome.IGNORED); return; } if (element == null) { if (doNotNotifyCacheReplicators) { LOG.debug("Element from replicated put is null. This happens because the element is a SoftReference" + " and it has been collected. Increase heap memory on the JVM or set -Xms to be the same as " + "-Xmx to avoid this problem."); } putObserver.end(PutOutcome.IGNORED); return; } if (element.getObjectKey() == null) { putObserver.end(PutOutcome.IGNORED); return; } element.resetAccessStatistics(); applyDefaultsToElementWithoutLifespanSet(element); backOffIfDiskSpoolFull(); element.updateUpdateStatistics(); boolean elementExists = false; if (useCacheWriter) { boolean notifyListeners = true; try { elementExists = !compoundStore.putWithWriter(element, cacheWriterManager); } catch (StoreUpdateException e) { elementExists = e.isUpdate(); notifyListeners = configuration.getCacheWriterConfiguration().getNotifyListenersOnException(); RuntimeException cause = e.getCause(); if (cause instanceof CacheWriterManagerException) { throw ((CacheWriterManagerException)cause).getCause(); } throw cause; } finally { if (notifyListeners) { notifyPutInternalListeners(element, doNotNotifyCacheReplicators, elementExists); } } } else { elementExists = !compoundStore.put(element); notifyPutInternalListeners(element, doNotNotifyCacheReplicators, elementExists); }
putObserver,只看名字,第一反應就知道,這也許是一個觀察者。Right!
private final OperationObserver<PutOutcome> putObserver = operation(PutOutcome.class).named("put").of(this).tag("cache").build();
附上相關調用的UML類圖,方便你們理解。
Cache類依賴StatisticBuilder的operation()方法,經過StatisticsManager來建立GeneralOperationStatistic類的一個實例。此實例實現了OperationObserver接口的begin()和end()方法。
putObserver.begin();
注:我的以爲這個地方的代碼實際上是運行不到的,由於它的addDerivedStatistic方法也沒有被調用到。或者是我疏忽了哪一個地方,還請知情人士貢獻一下。get的被用到了,下節我會詳細介紹。
putObserver.end(elementExists ? PutOutcome.UPDATED : PutOutcome.ADDED);
對應的操做:
注: increment()是org.terracotta.statistics.jsr166e.LongAdder類下面基於CAS原理實現的一個線程安全的自增方法。感興趣的朋友能夠reference這個link:
從咱們的調查結果中能夠看出,putObserver主要目的是統計put操做時ADDED,UPDATED,IGNORED的個數。 雖然結果很簡單,但更多的是讓咱們知道了它的設計理念以及思想。雖然實現起來很複雜,但代碼看起來仍是那麼的簡潔。