Ehcache中可以使用Cache来保存需要缓存的对像,但需要把对象封装在Element的实例里。
往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类图:
构造一个Element对象很简单,Cache没有什么复杂的操作。但看似简单的put操作,它的实现是还有点复杂。
Step 1: 开发者调用Cache的put方法。
cache.put(element);
Step 2: 对应的源码
public final void put(Element element) throws IllegalArgumentException, IllegalStateException,
CacheException {
put(element, false);
}
Step 3: 默认情况下doNotNotifyCacheReplicators的值是false.暂时先不讨论集群。
private void putAll(Collection<Element> elements, boolean doNotNotifyCacheReplicators) throws IllegalArgumentException,
IllegalStateException, CacheException {
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的个数。 虽然结果很简单,但更多的是让我们知道了它的设计理念以及思想。虽然实现起来很复杂,但代码看起来还是那么的简洁。
来源:oschina
链接:https://my.oschina.net/u/1050156/blog/186004