Cache模块

Cache模块

​ MyBatis中缓存模块相关代码位于cache包下,其中Cache接口是缓存模块中最核心的接口,它定义了所有缓存的基本行为。接口源码:

// Cache 接口 是缓存模块中最核心的接口,它定义了所有缓存的基本行为。
public interface Cache {

  /**
   * @return The identifier of this cache
   */
  // 该缓存对象的id
  String getId();

  /**
   * @param key Can be any object but usually it is a {@link CacheKey}
   * @param value The result of a select.
   */
  // 向缓存中添加数据,一般情况下, key是CacheKey,value是查询结果
  void putObject(Object key, Object value);

  /**
   * @param key The key
   * @return The object stored in the cache.
   */
  // 根据指定的 key ,在缓存中查找对应的结果对象
  Object getObject(Object key);

  /**
   * As of 3.3.0 this method is only called during a rollback
   * for any previous value that was missing in the cache.
   * This lets any blocking cache to release the lock that
   * may have previously put on the key.
   * A blocking cache puts a lock when a value is null
   * and releases it when the value is back again.
   * This way other threads will wait for the value to be
   * available instead of hitting the database.
   *
   *
   * @param key The key
   * @return Not used
   */
  // 删除 key 对应的缓存项
  Object removeObject(Object key);

  /**
   * Clears this cache instance.
   */
  // 清空缓存
  void clear();

  /**
   * Optional. This method is not called by the core.
   *
   * @return The number of elements stored in the cache (not its capacity).
   */
  // 缓存项的个数,该方法不会被 MyBatis 核心代码使用,所以可提供空实现
  int getSize();

  /**
   * Optional. As of 3.2.6 this method is no longer called by the core.
   * <p>
   * Any locking needed by the cache must be provided internally by the cache provider.
   *
   * @return A ReadWriteLock
   */
  // 获取读写锁,该方法不会被 MyBatis 核心代码使用,所以可提供空实现
  default ReadWriteLock getReadWriteLock() {
    return null;
  }

}

​ 其余扩展行为均使用装饰器模式实现。以下列举出主要的类。源码如下:

/**
 *    Copyright ${license.git.copyrightYears} the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

/**
 * @author Clinton Begin
 */
/**
 * Cache接口的实现类有多个,但大部分都是装饰器,只有 PerpetualCache 提供了 Cache 接口的基本实现。<br/>
 * PerpetualCache 在缓存模块中扮演着 ConcreteComponent 的角色,其实现比较简单,底层使<br/>
 * HashMap 记录缓存项,也是通过该 HashMap 对象的方法实现的 Cache 接口中定义的相应方法。<br/>
 */
public class PerpetualCache implements Cache {

  // Cache 对象的唯一标识
  private final String id;

  // 用于记录缓存项的 Map 对象
  private Map<Object, Object> cache = new HashMap<>();

  public PerpetualCache(String id) {
    this.id = id;
  }

  @Override
  public String getId() {
    return id;
  }

  // 下面所有的方法都是通过 cache 字段记录这个 HashMap 对象的相应方法实现的

  @Override
  public int getSize() {
    return cache.size();
  }

  @Override
  public void putObject(Object key, Object value) {
    cache.put(key, value);
  }

  @Override
  public Object getObject(Object key) {
    return cache.get(key);
  }

  @Override
  public Object removeObject(Object key) {
    return cache.remove(key);
  }

  @Override
  public void clear() {
    cache.clear();
  }

  // ... 重写 equals ()方法和 hashCode ()方法,两者都只关心 id 字段,并不关心 cache 字段(略)

  @Override
  public boolean equals(Object o) {
    if (getId() == null) {
      throw new CacheException("Cache instances require an ID.");
    }
    if (this == o) {
      return true;
    }
    if (!(o instanceof Cache)) {
      return false;
    }

    Cache otherCache = (Cache) o;
    return getId().equals(otherCache.getId());
  }

  @Override
  public int hashCode() {
    if (getId() == null) {
      throw new CacheException("Cache instances require an ID.");
    }
    return getId().hashCode();
  }

}

/**
 *    Copyright ${license.git.copyrightYears} the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache.decorators;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.Deque;
import java.util.LinkedList;

import org.apache.ibatis.cache.Cache;

/**
 * Soft Reference cache decorator
 * Thanks to Dr. Heinz Kabutz for his guidance here.
 *
 * @author Clinton Begin
 */
public class SoftCache implements Cache {
  // SoftCache 中,最近使用的一部分缓存项不会被 GC 回收,这就是通过将其 value 添加到
  // hardLinksToAvoidGarbageCollection 集合中实现的(即有强引用指向其 value)
  // hardLinksToAvoidGarbageCollection 集合是 LinkedList<Object >类型
  private final Deque<Object> hardLinksToAvoidGarbageCollection;
  // ReferenceQueue 引用队列,用于记录已经被GC回收的缓存项所对应的SoftEntry对象
  private final ReferenceQueue<Object> queueOfGarbageCollectedEntries;
  private final Cache delegate;// 底层被装饰的底层 Cache 对象
  private int numberOfHardLinks;// 强连接的个数, 认值是 256

  public SoftCache(Cache delegate) {
    this.delegate = delegate;
    this.numberOfHardLinks = 256;
    this.hardLinksToAvoidGarbageCollection = new LinkedList<>();
    this.queueOfGarbageCollectedEntries = new ReferenceQueue<>();
  }

  @Override
  public String getId() {
    return delegate.getId();
  }

  @Override
  public int getSize() {
    removeGarbageCollectedItems();
    return delegate.getSize();
  }


  public void setSize(int size) {
    this.numberOfHardLinks = size;
  }

  @Override
  public void putObject(Object key, Object value) {
    removeGarbageCollectedItems();// 清除已经被 GC 回收的缓存项
    // 向缓存中添加缓存项
    delegate.putObject(key, new SoftEntry(key, value, queueOfGarbageCollectedEntries));
  }

  /**
   * 除了从缓存 对应 value ,处理被 GC 回收的 value 对应的
   * 缓存项 还会更新 hardLinksToAvoidGarbageCollection 集合
   */
  @Override
  public Object getObject(Object key) {
    Object result = null;
    @SuppressWarnings("unchecked") // assumed delegate cache is totally managed by this cache
    // 从缓存 查找对应的缓存项
    SoftReference<Object> softReference = (SoftReference<Object>) delegate.getObject(key);
    if (softReference != null) {// 检测缓存 是否 对应的缓存项
      result = softReference.get();// 获取 SoftRef erence 引用的 value
      if (result == null) {// 已经被GC回收
        delegate.removeObject(key);// 从缓存 清除对应的缓存项
      } else {// 未被GC回收
        // See #586 (and #335) modifications need more than a read lock
        synchronized (hardLinksToAvoidGarbageCollection) {
          // 缓存项 value hardLinksToAvoidGarbageCollection 集合中保存
          hardLinksToAvoidGarbageCollection.addFirst(result);
          if (hardLinksToAvoidGarbageCollection.size() > numberOfHardLinks) {
            // 超过 nurnberOfHardLinks ,则将最老的缓存项从
            // hardLinksToAvoidGarbageCollection 集合中清除,有点类似于先进先出队f1]
            hardLinksToAvoidGarbageCollection.removeLast();
          }
        }
      }
    }
    return result;
  }

  @Override
  public Object removeObject(Object key) {
    removeGarbageCollectedItems();
    return delegate.removeObject(key);
  }

  @Override
  public void clear() {
    synchronized (hardLinksToAvoidGarbageCollection) {
      hardLinksToAvoidGarbageCollection.clear();// 清理强引用集合
    }
    removeGarbageCollectedItems();// 清理被 GC 回收的缓存项
    delegate.clear();// 清理底层 delegate 缓存中的缓存项
  }

  private void removeGarbageCollectedItems() {
    SoftEntry sv;
    // 造历 queueOfGarbageCollectedEntries 集合
    while ((sv = (SoftEntry) queueOfGarbageCollectedEntries.poll()) != null) {
      delegate.removeObject(sv.key);// 将已经被 GC 回收的 value 对象对 存项清除
    }
  }

  /**
   * SoftCache 中缓存项的 value SoftEn町对象, SoftEntry 继承 Soft:Reference 其中指向
   * key 的引用是强引用, 而指向 value 的引用是软引用
   */
  private static class SoftEntry extends SoftReference<Object> {
    private final Object key;

    SoftEntry(Object key, Object value, ReferenceQueue<Object> garbageCollectionQueue) {
      // 指向value 的引用是软引用,且关联了引用队列
      super(value, garbageCollectionQueue);
      this.key = key;// 强引用
    }
  }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值