深刻理解Ehcache系列(五)

        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:

 http://grepcode.com/file/repo1.maven.org/maven2/net.sf.ehcache/ehcache/2.7.2/org/terracotta/statistics/jsr166e/LongAdder.java#LongAdder.add%28long%29

     

       从咱们的调查结果中能够看出,putObserver主要目的是统计put操做时ADDED,UPDATED,IGNORED的个数。 虽然结果很简单,但更多的是让咱们知道了它的设计理念以及思想。虽然实现起来很复杂,但代码看起来仍是那么的简洁。

相关文章
相关标签/搜索