源码分析:Guava Cache的使用以及源码分析-Builder

Guava Cache是性能非常高的本地缓存,其他的还有ehcache等。相对于本地缓存还有分布式缓存,其实就是独立于业务的第三方应用,比如redis、memcahe或者自己弄个机器加大内存,把它当作另外一个集群的分布式缓存同样是可以的,但是要做到高可用不是一件简单的事情。另外,内存缓存有个不可避免的问题是易丢失,所以要持久化的就老老实实弄一个redis或者直接入库。这里主要记录是标题的内容,话不多直接开始,先是使用,然后在看builder,学习谷歌大神写的代码得分好篇文章了,这篇文章主要就是上述两者:

Guava Cache的使用

使用相对简单,这也是它流传广泛的一个重要原因吧,直接上平时使用的代码:

  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

这里我们可以看到LoadingCache是通过newBuilder的方式建立的,这里用到的是Builder设计模式,先看上构建cache的类似实现,这是摘自这篇文章的一个例子,这个很好理解,一个bean中有个静态内部类Builder,其中的属性就是外部person对应的属性,它对外暴露属性,并把返回Buildler自身,直到使用bulid(),new出外部类。

/**
 * @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;
    }
}

下边看一下经典的Builder是如何实现的,下边是UML类图

从上图可以看到,经典Buider模式中有四个角色:

1、要建造的产品Product -- LoadingCache

2、抽象的Builder -- 我们的例子中略去了抽象层,我们可以随时抽象

3、Builder的具体实现ConcreteBuilder -- 对应maximumSize、expireAfterWrite等

4、使用者Director -- 对应的类

有了上述的这些点,我们来看下guava cache的Builder代码的实现,首先是创建一个CacheBuilder

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

剩下的就是利用各种属性进行赋值,我们这里只使用其中一个作为例子


  /**
   * 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;
  }

第三步就是调用build()方法进行构建LocalCache类

  /**
   * 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是一个抽象类,第一个例子中返回了它的一个实现

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

至此guava localcache对象便生成了,嗯,这只是很简单的第一步。

发布了223 篇原创文章 · 获赞 308 · 访问量 84万+

猜你喜欢

转载自blog.csdn.net/maoyeqiu/article/details/93375606