Source analysis: Guava Cache usage and source code analysis -Builder

Guava Cache is a very high performance local cache, there are other ehcache and so on. Relative to the local cache as well as distributed caching, in fact, independent of third-party business applications, such as redis, memcahe own or get hold of the machine to increase memory and treat it as another cluster of distributed cache is also possible, but to achieve high availability is not a simple matter. In addition, there is a memory cache inevitable question is easy to lose, so be persistent honestly get a redis or direct storage. Here are the main content title record, the word does not just start, first use and then look at builder, the god of learning to write code that Google scores good article, and the article is mainly the above two:

Use of Guava Cache

Using relatively simple, which is its wide spread is an important reason for it, usually used directly on the code:

  public LoadingCache<String, String> serviceCache =
      CacheBuilder.newBuilder().maximumSize(20000).expireAfterWrite(10, TimeUnit.SECONDS)
          .recordStats().build(new CacheLoader<String, String>() {
        @Override
        public String load(String key) {
          return service.query(key);
        }
      });

Builder

Here we can see LoadingCache be established by newBuilder way, is used here Builder design mode, look on the build cache of similar implementations, this is an excerpt from the article an example, this is well understood, in a bean there is a static inner class Builder, wherein the attribute is an attribute corresponding to an external person, it is exposed to the external properties and to return Buildler itself, until use bulid (), new outside the class.

/**
 * @author SunKing1927 2015年11月2日
 *         Java Builder模式
 */
public class Person {
    private String name;
    private int age;
    private boolean sex;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public boolean isSex() {
        return sex;
    }

    public static class Builder {
        private String name;
        private int age;
        private boolean sex;

        public Builder name(String n) {
            name = n;
            return this;
        }

        public Builder age(int a) {
            age = a;
            return this;
        }

        public Builder sex(boolean s) {
            sex = s;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    private Person(Builder builder) {
        name = builder.name;
        age = builder.age;
        sex = builder.sex;
    }
}

Under watching how the classic Builder is achieved, below is a UML class diagram

You can see from the chart, the classic Buider mode has four roles:

1, to build products Product - LoadingCache

2, abstract Builder - our case omitted abstraction layer, we can abstract at any time

3, Builder specific implementation ConcreteBuilder - corresponds maximumSize, expireAfterWrite etc.

4, the user Director - corresponding class

With these points above, we look at the code to achieve Builder guava cache, the first is to create a CacheBuilder

  /**
   * 静态公共方法暴露出来进行构建
   */
  public static CacheBuilder<Object, Object> newBuilder() {
    return new CacheBuilder<Object, Object>();
  }

The rest is assigned using a variety of attributes, only one of which we here as an example


  /**
   * 1、对参数进行校验
   * 2、赋值之后返回CacheBuilder对象本身,和上边的Person本身是很想的
   */
  public CacheBuilder<K, V> maximumSize(long size) {
    checkState(this.maximumSize == UNSET_INT, "maximum size was already set to %s",
        this.maximumSize);
    checkState(this.maximumWeight == UNSET_INT, "maximum weight was already set to %s",
        this.maximumWeight);
    checkState(this.weigher == null, "maximum size can not be combined with weigher");
    checkArgument(size >= 0, "maximum size must not be negative");
    this.maximumSize = size;
    return this;
  }

  public CacheBuilder<K, V> expireAfterWrite(long duration, TimeUnit unit) {
    checkState(expireAfterWriteNanos == UNSET_INT, "expireAfterWrite was already set to %s ns",
        expireAfterWriteNanos);
    checkArgument(duration >= 0, "duration cannot be negative: %s %s", duration, unit);
    this.expireAfterWriteNanos = unit.toNanos(duration);
    return this;
  }

The third step is to call the build () method to build LocalCache class

  /**
   * 1、LocalCache调用其静态内部类LocalLoadingCache的构造方法new了一个LocalCache,这一点和上边的person很像
   */
  public <K1 extends K, V1 extends V> LoadingCache<K1, V1> build(
      CacheLoader<? super K1, V1> loader) {
    checkWeightWithWeigher();
    return new LocalCache.LocalLoadingCache<K1, V1>(this, loader);
  }

  static class LocalLoadingCache<K, V>
      extends LocalManualCache<K, V> implements LoadingCache<K, V> {

    LocalLoadingCache(CacheBuilder<? super K, ? super V> builder,
        CacheLoader<? super K, V> loader) {
      super(new LocalCache<K, V>(builder, checkNotNull(loader)));
    }
  }

  /**
   * new LocalCache的过程就是把builder中的属性赋值到LocalCache中属性的过程
   */
  LocalCache(
      CacheBuilder<? super K, ? super V> builder, @Nullable CacheLoader<? super K, V> loader) {
    concurrencyLevel = Math.min(builder.getConcurrencyLevel(), MAX_SEGMENTS);

    keyStrength = builder.getKeyStrength();
    valueStrength = builder.getValueStrength();

    keyEquivalence = builder.getKeyEquivalence();
    valueEquivalence = builder.getValueEquivalence();

    maxWeight = builder.getMaximumWeight();
    weigher = builder.getWeigher();
    expireAfterAccessNanos = builder.getExpireAfterAccessNanos();
    expireAfterWriteNanos = builder.getExpireAfterWriteNanos();
    refreshNanos = builder.getRefreshNanos();

    removalListener = builder.getRemovalListener();
    removalNotificationQueue = (removalListener == NullListener.INSTANCE)
        ? LocalCache.<RemovalNotification<K, V>>discardingQueue()
        : new ConcurrentLinkedQueue<RemovalNotification<K, V>>();

    ticker = builder.getTicker(recordsTime());
    entryFactory = EntryFactory.getFactory(keyStrength, usesAccessEntries(), usesWriteEntries());
    globalStatsCounter = builder.getStatsCounterSupplier().get();
    defaultLoader = loader;

    int initialCapacity = Math.min(builder.getInitialCapacity(), MAXIMUM_CAPACITY);
    if (evictsBySize() && !customWeigher()) {
      initialCapacity = Math.min(initialCapacity, (int) maxWeight);
    }

CacheLoader is an abstract class, the first example of an implementation which returns

/**
 * CacheLoader是一个抽象类,返回的是CacheLoader的一个实现,至于其中的方法什么时候调用,完全看localCache的需要
 */
 new CacheLoader<String, String>() { 
   @Override 
    public String load(String key) { 
     return service.query(key); 
   } 
 }

So far guava localcache objects will be generated, ah, this is just a very simple first step.

Published 223 original articles · won praise 308 · views 840 000 +

Guess you like

Origin blog.csdn.net/maoyeqiu/article/details/93375606