Custom Cache Base on Google Guava Cache

上篇咱们介绍了Spring之Caffeine缓存的简单了解,这里仅仅是讲述了一个小小的应用场景及简化开发,关于更多其他应用接下来有时间再聊(比如:结合Spring-Data-Redis做多层缓存结构等等),今天咱们学习基于Google Guava来开发一款自己的轻量级内存缓存,像Caffeine一样最终交由Spring来管理咱们自己的缓存.

老习惯开发语言Kotlin硬刚:

1.缓存管理接口

/**
 * 可维护缓存接口
 */
interface MaintainableCache<T> {
    /**
     * 添加缓存对象
     */
    fun add(obj: T)

    /**
     * 删除缓存对象
     */
    fun delete(obj: T)

    /**
     * 清空所有缓存
     */
    fun clear()
}
/**
 * 创建内存缓存接口缓存
 */
interface InternalCacheable<T> {
    /**
     * 创建唯一值缓存
     */
    fun <K> uniqueCache(keyBuilder: Function<T,K>) : InternalCache<K,T>

    /**
     * 创建多值缓存
     */
    fun <K> multipleCache(keyBuilder: Function<T,K>) : InternalCache<K, Collection<T>>
}
/**
 * 根据key值查询数据
 */
interface InternalCache<K,V> {
    /**
     * 根据key获取对应值
     */
    fun get(key: K): V?

    /**
     * 判断key是否存在
     */
    fun ifPresent(key: K): Boolean

}

2.接口实现,唯一键值实现Map结构仅保证key唯一,value可能重复,此处使用了Google的HashBiMap来保证键值都唯一,当然实际应用中key值一般均为ID或代表唯一对象的标识,只要存储的value对象中含有唯一标识,可认为同一对象,当新值put进来时会替换之前的数据,以做到更新缓存的目的,无法辨别存储对象是否含有key同值的唯一标识时,此时,HashBiMap就起到了更新缓存的作用了.

/**
 * 唯一键,值缓存实现
 * 使用google guava HashBiMap 保证K,V存储唯一
 */
class UniqueCacheable<K,V>(var keyBuilder: Function<V,K>):InternalCache<K,V>,MaintainableCache<V> {
    private var data = HashBiMap.create<K,V>()
    companion object {
        fun <K,V> create(keyBuilder: Function<V,K>) = UniqueCacheable(keyBuilder)
    }

    override fun get(key: K): V? = data[key]

    override fun ifPresent(key: K)= data.containsKey(key)

    override fun add(obj: V) {
        val key = keyBuilder.apply(obj)
        if (key.isNull()) return
        data[key] = obj
    }

    override fun delete(obj: V) {
        val key = keyBuilder.apply(obj)
        if (key.isNull()) return
        data.remove(key,obj)
    }

    override fun clear() {
        data.clear()
    }

}
/**
 * 可维护缓存实现
 */
class MaintainableCacheable<T>:InternalCacheable<T>,MaintainableCache<T> {
    private val list = mutableListOf<MaintainableCache<T>>()

    override fun <K> uniqueCache(keyBuilder: Function<T, K>) = UniqueCacheable.create(keyBuilder).apply { list.add(this) }

    override fun add(obj: T) = list.forEach { it.add(obj) }

    override fun delete(obj: T) = list.forEach { it.delete(obj) }

    override fun clear() = list.forEach { it.clear() }
}

3.Map实现缓存,这里的Map继承了Google的ForwardingMap,作为唯一键值实现,多值也可以继承ForwardingMultimap,Java类无多继承,所以本文只继承了ForwardingMap,而多值可以具体另外实现,有兴趣同学可以尝试下一键多值.此处仅仅是以map为结构的缓存策略,如有其他(如:List,Set)也可以具体实现,需要说明的是除map结构外,其他结构类型在add数据之前应先remove之前数据,否则无法保证键值唯一.

class CacheableMap<K,V>(var data: Map<K,V>): ForwardingMap<K,V>(),InternalCacheable<V> {
    private val maintainableCacheable = MaintainableCacheable<V>()
    companion object {
        fun <K,V> create() = create(mutableMapOf<K,V>())
        fun <K,V> create(data: Map<K,V>) = CacheableMap(data)
    }
    override fun delegate() = data

    override fun <K> uniqueCache(keyBuilder: Function<V, K>) = maintainableCacheable.uniqueCache(keyBuilder)
    //TODO implement multipleCache interface
    override fun clear() {
        super.clear()
        maintainableCacheable.clear()
    }

    override fun put(key: K, value: V) =
        super.put(key, value).apply {
            // List/Set remove old value
            maintainableCacheable.add(value)
        }

    override fun remove(key: K) = super.remove(key).apply {
            if (this.isNotNull()) maintainableCacheable.delete(this!!)
    }

}

4.使用示例中,对象a可以认为是old data,b为new data当创建了uniqueCache和multipleCache查看输出的不同,有兴趣的同学,可以另创建不含有id,名称相同的dto,看是否能存储到内存缓存中.

fun main(args: Array<String>) {
    val caches = CacheableMap.create<Long,A>()
    val a = A(1,"张三")
    val b = A(1,"李四")
    val unique = caches.uniqueCache(Function(A::id))
    var multi = caches.multipleCache(Function(A::id))
    caches[a.id] = a
    caches[a.id] = b


    println("unique cache is ${unique.get(a.id)}")
    println("multi cache is ${multi.get(a.id)}")

}
class A(
    var id: Long = 0,
    var a: String=""
):Serializable{
    override fun toString(): String {
        return "A(id=$id, a='$a')"
    }
}

5.测试结果:

unique cache is A(id=1, a='李四')
multi cache is [A(id=1, a='张三'), A(id=1, a='李四')]

6.测试结果分析uniqueCache:key相同时,新数据会覆盖老数据;multipleCache会放入集合之中.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值