Skip to content

核心接口参考

本页面提供 CoCache 框架中每个核心接口的完整参考。接口按模块和功能区域进行组织。

缓存 API 接口 (cocache-api)

Cache<K, V>

组合读写操作的根缓存接口。

方面详情源码
me.ahoo.cache.api--
继承CacheGetter<K, V>CacheSetter<K, V>--
类型参数K -- 缓存键类型,V -- 缓存值类型--
源文件--Cache.kt:21
kotlin
interface Cache<K, V> : CacheGetter<K, V>, CacheSetter<K, V>

Cache<K, V> 是一个纯组合接口。所有缓存层 -- ClientSideCacheDistributedCacheCoherentCacheJoinCache -- 最终都实现此接口。

CacheGetter<K, V>

只读缓存访问接口。

方法签名说明源码
getCachefun getCache(key: K): CacheValue<V>?返回完整的 CacheValue 包装(包括 TTL 元数据),不存在时返回 nullCacheGetter.kt:21
getoperator fun get(key: K): V?返回解包后的值或 null。去除 TTL 和缺失守卫信息CacheGetter.kt:29
getTtlAtfun getTtlAt(key: K): Long?返回过期时间戳(秒),键不存在时返回 nullCacheGetter.kt:37

CacheSetter<K, V>

写入和驱逐接口。

方法签名说明源码
setoperator fun set(key: K, ttlAt: Long, value: V)使用显式过期时间戳设置值CacheSetter.kt:18
setoperator fun set(key: K, value: V)使用缓存的默认 TTL 配置设置值CacheSetter.kt:20
setCachefun setCache(key: K, value: CacheValue<V>)设置预构造的 CacheValue(包含 TTL 和缺失守卫元数据)CacheSetter.kt:22
evictfun evict(key: K)从缓存中移除条目CacheSetter.kt:29

CacheValue<V>

将缓存值与 TTL 和缺失守卫元数据包装在一起。

属性/方法类型说明源码
valueV实际的缓存值CacheValue.kt:21
ttlAtLong过期时间戳(秒)(ChronoUnit.SECONDSCacheValue.kt:28
isMissingGuardBoolean该值是否为缺失键的占位符(防止缓存穿透)CacheValue.kt:30

继承 TtlAt,获得 isForeverisExpiredexpiredDuration 属性。

默认实现DefaultCacheValue -- 伴生对象工厂方法:forever()ttlAt()missingGuard()

TtlAt

基于绝对时间戳的生存时间管理接口。

属性类型说明源码
ttlAtLong绝对过期时间(秒)TtlAt.kt:23
isForeverBoolean此条目是否永不过期TtlAt.kt:29
isExpiredBoolean当前时间是否已超过 ttlAtTtlAt.kt:30
expiredDurationDuration距过期还有多少时间,以 java.time.Duration 表示TtlAt.kt:31

默认实现ComputedTtlAt -- 提供静态工具方法 at(ttl, amplitude)isForever(ttl)

NamedCache

通过逻辑名称标识缓存。

属性类型说明源码
cacheNameString缓存逻辑名称,用于 Bean 注册和事件路由NamedCache.kt:21

ClientSideCache<V>

L2 客户端(进程内)缓存接口。

方面详情源码
继承Cache<String, V>--
键类型String(通过 KeyConverter 转换)--
源文件--ClientSideCache.kt:22
属性/方法类型说明
sizeLong客户端缓存中当前的条目数
clearfun clear()移除本地缓存中的所有条目

实现

实现说明模块
MapClientSideCache基于 ConcurrentHashMap,无驱逐策略cocache-core
GuavaClientSideCache基于 Guava Cache,支持可配置的大小/时间驱逐cocache-core
CaffeineClientSideCache基于 Caffeine Cache,支持可配置的大小/时间驱逐cocache-core

CacheSource<K, V>

L0 数据源加载器接口。当 L2 和 L1 缓存都未命中时调用。

方法签名说明源码
loadCacheValuefun loadCacheValue(key: K): CacheValue<V>?从底层数据源加载值。键不存在时返回 null。可能抛出 TimeoutExceptionCacheSource.kt:24
伴生方法说明
noOp()返回始终返回 null 的单例 NoOpCacheSource

默认实现NoOpCacheSource -- 对象单例,始终返回 null

核心模块接口 (cocache-core)

DistributedCache<V>

L1 分布式(共享)缓存接口。

方面详情源码
继承ComputedCache<String, V>AutoCloseable--
键类型String--
源文件--DistributedCache.kt:22

继承 ComputedCache 获得默认的 get()set()getTtlAt() 实现,继承 AutoCloseable 用于资源清理。

实现

实现说明模块
MockDistributedCache用于测试的内存模拟cocache-core
RedisDistributedCache使用 StringRedisTemplate 的 Redis 分布式缓存cocache-spring-redis

DistributedClientId

在分布式系统中标识缓存客户端实例。

属性类型说明源码
clientIdString此缓存客户端实例的唯一标识符(用于避免处理自己发布的事件)DistributedClientId.kt:21

默认客户端 ID 生成器:HostClientIdGenerator(使用主机地址)、UUIDClientIdGenerator(随机 UUID)。

ComputedCache<K, V>

Cache 方法提供计算默认实现,桥接原始 CacheValue 访问与用户友好的 get/set 操作。

方面详情源码
继承Cache<K, V>TtlConfiguration--
源文件--ComputedCache.kt:20

关键行为:

  • get(key) -- 调用 getCache(key),如果为缺失守卫或已过期则返回 null
  • getTtlAt(key) -- 调用 getCache(key),如果为缺失守卫则返回 null
  • set(key, value) -- 使用默认 TTL + 幅度抖动创建 DefaultCacheValue
  • set(key, ttlAt, value) -- 使用显式 TTL 创建 DefaultCacheValue

CoherentCache<K, V>

二级一致性缓存的中心接口,组合了所有缓存关注点。

方面详情源码
继承ComputedCache<K, V>DistributedClientIdNamedCacheCacheEvictedSubscriber--
源文件--CoherentCache.kt:25
属性类型说明
cacheEvictedEventBusCacheEvictedEventBus用于发布/接收驱逐事件的事件总线
clientSideCacheClientSideCache<V>L2 本地缓存
distributedCacheDistributedCache<V>L1 分布式缓存
keyFilterKeyFilter用于防止缓存穿透的布隆过滤器
keyConverterKeyConverter<K>将类型化键转换为字符串键
cacheSourceCacheSource<K, V>L0 数据源

默认实现DefaultCoherentCache -- 实现了细粒度锁以防止缓存击穿、缺失守卫缓存以防止缓存穿透,以及事件驱动的一致性。

DefaultCoherentCache 细粒度锁

DefaultCoherentCache.getCache() 方法使用逐键锁,当多个线程请求相同的缺失键时防止缓存击穿:

mermaid
flowchart TB
    subgraph Locking["细粒度锁流程"]
        style Locking fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        Start["getCache(key)"]
        L2Check["检查 L2<br>(ClientSideCache)"]
        L2Hit{"L2 命中?"}
        KFCheck["KeyFilter.notExist?"]
        KFMiss{"键不存在?"}
        L1Check["检查 L1<br>(DistributedCache)"]
        L1Hit{"L1 命中?"}
        Lock["获取逐键锁<br>synchronized(keyLock)"]
        L2Recheck["重新检查 L2<br>(双重检查)"]
        L2RHit{"L2 现在命中?"}
        L0Load["从 L0 加载<br>(CacheSource)"]
        L0Found{"找到值?"}
        SetBoth["设置 L2 + L1<br>发布事件"]
        SetGuard["设置 MissingGuard<br>在 L2 + L1 中"]
        Return["返回值"]

        Start --> L2Check
        L2Check --> L2Hit
        L2Hit -- "是" --> Return
        L2Hit -- "否" --> KFCheck
        KFCheck --> KFMiss
        KFMiss -- "是" --> SetGuard
        KFMiss -- "否" --> L1Check
        L1Check --> L1Hit
        L1Hit -- "是" --> SetBoth
        L1Hit -- "否" --> Lock
        Lock --> L2Recheck
        L2Recheck --> L2RHit
        L2RHit -- "是" --> Return
        L2RHit -- "否" --> L0Load
        L0Load --> L0Found
        L0Found -- "是" --> SetBoth
        L0Found -- "否" --> SetGuard
        SetBoth --> Return
        SetGuard --> Return
    end

CoherentCacheConfiguration<K, V>

包含创建 CoherentCache 所需的所有配置的数据类。

属性类型默认值源码
cacheNameString(必需)CoherentCacheConfiguration.kt:27
clientIdString(必需)CoherentCacheConfiguration.kt:28
keyConverterKeyConverter<K>(必需)CoherentCacheConfiguration.kt:29
distributedCacheDistributedCache<V>(必需)CoherentCacheConfiguration.kt:30
clientSideCacheClientSideCache<V>MapClientSideCache()CoherentCacheConfiguration.kt:31
cacheSourceCacheSource<K, V>CacheSource.noOp()CoherentCacheConfiguration.kt:32
keyFilterKeyFilterNoOpKeyFilterCoherentCacheConfiguration.kt:33

缓存一致性接口

CacheEvictedEventBus

用于缓存驱逐事件的发布-订阅事件总线,确保分布式缓存一致性。

方法签名说明源码
publishfun publish(event: CacheEvictedEvent)向所有订阅者发布驱逐事件CacheEvictedEventBus.kt:20
registerfun register(subscriber: CacheEvictedSubscriber)注册订阅者以接收驱逐事件CacheEvictedEventBus.kt:21
unregisterfun unregister(subscriber: CacheEvictedSubscriber)移除订阅者使其不再接收事件CacheEvictedEventBus.kt:22

实现

实现范围说明模块
GuavaCacheEvictedEventBus单 JVM使用 Guava EventBus 进行进程内发布/订阅cocache-core
NoOpCacheEvictedEventBus空操作单例,事件被丢弃cocache-core
RedisCacheEvictedEventBus分布式使用 Redis Pub/Sub 进行跨实例事件传播cocache-spring-redis

CacheEvictedSubscriber

响应缓存驱逐事件的组件接口。

方法签名说明源码
onEvictedfun onEvicted(cacheEvictedEvent: CacheEvictedEvent)收到缓存驱逐事件时调用CacheEvictedSubscriber.kt:23

继承 NamedCache,使订阅者知道自己属于哪个缓存。

CacheEvictedEvent

表示缓存驱逐事件的数据类。

属性类型说明源码
cacheNameString条目被驱逐的缓存名称CacheEvictedEvent.kt:21
keyString被驱逐的缓存键(字符串转换后)CacheEvictedEvent.kt:28
publisherIdString发布事件的实例的客户端 IDCacheEvictedEvent.kt:34

JoinCache 接口 (cocache-api)

JoinCache<K1, V1, K2, V2>

将两个缓存值组合为单个 JoinValue 结果。

方面详情源码
继承Cache<K1, JoinValue<V1, K2, V2>>--
源文件--JoinCache.kt:23
属性/方法类型说明
joinKeyExtractorJoinKeyExtractor<V1, K2>从第一个值中提取关联键
evictfun evict(firstKey: K1, joinKey: K2)同时从第一个缓存和关联缓存中驱逐条目

JoinValue<V1, K2, V2>

将主值与关联的次要值组合的结果类型。

属性类型说明源码
firstValueV1主缓存值JoinValue.kt:16
joinKeyK2用于查找次要值的键JoinValue.kt:17
secondValueV2?关联的次要值(可为 null,未找到时)JoinValue.kt:18

默认实现DefaultJoinValue

JoinKeyExtractor<V1, K2>

用于从主值中提取关联键的函数式接口。

方法签名说明源码
extractfun extract(firstValue: V1): K2从第一个缓存值中提取关联键JoinKeyExtractor.kt:8

实现ExpJoinKeyExtractor(基于 SpEL 表达式,在 cocache-core 中)。

JoinCache 流程

JoinCache 检索流程通过获取主值、提取关联键、然后获取次要值来工作:

mermaid
sequenceDiagram
autonumber
    participant Caller as 调用方
    participant JC as SimpleJoinCache
    participant FC as firstCache
    participant JKE as JoinKeyExtractor
    participant SC as secondCache (joinCache)

    Caller->>JC: getCache(firstKey)
    JC->>FC: getCache(firstKey)
    FC-->>JC: firstCacheValue
    JC->>JKE: extract(firstValue)
    JKE-->>JC: joinKey
    JC->>SC: getCache(joinKey)
    SC-->>JC: secondCacheValue
    JC-->>Caller: JoinValue(firstValue, joinKey, secondValue)

键过滤器接口

KeyFilter

缓存键过滤器接口,旨在适配布隆过滤器以防止缓存击穿。

方法签名说明源码
notExistfun notExist(key: String): Boolean如果键确定不在数据源中,则返回 trueKeyFilter.kt:22

实现

实现说明模块
NoOpKeyFilter始终返回 false(无过滤)cocache-core
BloomKeyFilter使用 Guava BloomFilter 进行概率性键存在性检查cocache-core

客户端缓存实现

mermaid
classDiagram
    direction LR

    class ClientSideCache~V~ {
        <<interface>>
        +size: Long
        +clear()
    }
    class Cache~String,V~ {
        <<interface>>
    }
    class MapClientSideCache~V~ {
        -cache: ConcurrentHashMap
        +getCache(key) CacheValue
        +setCache(key, value)
        +evict(key)
        +clear()
    }
    class GuavaClientSideCache~V~ {
        -cache: Guava~Cache~
        +getCache(key) CacheValue
        +setCache(key, value)
        +evict(key)
        +clear()
    }
    class CaffeineClientSideCache~V~ {
        -cache: Caffeine~Cache~
        +getCache(key) CacheValue
        +setCache(key, value)
        +evict(key)
        +clear()
    }

    Cache <|-- ClientSideCache
    ClientSideCache <|.. MapClientSideCache
    ClientSideCache <|.. GuavaClientSideCache
    ClientSideCache <|.. CaffeineClientSideCache

    style ClientSideCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style Cache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style MapClientSideCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style GuavaClientSideCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CaffeineClientSideCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

键转换器接口

KeyConverter<K>

将类型化的缓存键转换为用于存储的字符串键。

方法签名说明源码
toStringKeyfun toStringKey(sourceKey: K): String将类型化键转换为带前缀的字符串表示KeyConverter.kt:8

实现

实现说明源码
ToStringKeyConverter<K>简单的 keyPrefix + sourceKey.toString()ToStringKeyConverter.kt:20
ExpKeyConverter<K>基于 SpEL 表达式的键生成,带前缀ExpKeyConverter.kt:24

MissingGuard

通过使用哨兵标记缓存 null/缺失值来防止缓存穿透。

常量/扩展说明源码
STRING_VALUE = "_nil_"StringSetMap 类型缺失值的哨兵字符串MissingGuard.kt:18
Any?.isMissingGuard检查值是否为缺失守卫的扩展属性MissingGuard.kt:19

工厂接口

所有工厂接口遵循共同的模式:接受 CoCacheMetadata(或 JoinCacheMetadata)并生成相应的缓存组件。

工厂接口产出源码
CacheFactory按名称/类型的命名 Cache 实例CacheFactory.kt:19
CoherentCacheFactoryCoherentCacheConfiguration 创建 CoherentCacheCoherentCacheFactory.kt:16
CacheProxyFactory基于代理的 Cache 实现CacheProxyFactory.kt:19
ClientSideCacheFactoryClientSideCache<V> 实例ClientSideCacheFactory.kt:19
DistributedCacheFactoryDistributedCache<V> 实例DistributedCacheFactory.kt:18
CacheSourceFactoryCacheSource<K, V> 实例CacheSourceFactory.kt:19
KeyConverterFactoryKeyConverter<K> 实例KeyConverterFactory.kt:18
JoinKeyExtractorFactoryJoinKeyExtractor<V1, K2> 实例JoinKeyExtractorFactory.kt:19
JoinCacheProxyFactory基于代理的 JoinCache 实现JoinCacheProxyFactory.kt:19

接口关系图

下图展示了工厂接口如何组合以产生可工作的缓存:

mermaid
graph TB
    subgraph Inputs["输入"]
        style Inputs fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        Meta["CoCacheMetadata<br>(从 @CoCache 解析)"]
    end

    subgraph Factories["工厂层"]
        style Factories fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        KCF["KeyConverterFactory"]
        CSF["ClientSideCacheFactory"]
        DCF["DistributedCacheFactory"]
        CSrcF["CacheSourceFactory"]
        CCGF["CoherentCacheFactory"]
        CPF["CacheProxyFactory"]
    end

    subgraph Products["产生的组件"]
        style Products fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        KC["KeyConverter"]
        CSC["ClientSideCache"]
        DC["DistributedCache"]
        CSrc["CacheSource"]
        CC["CoherentCache"]
        Proxy["缓存代理"]
    end

    Meta --> KCF
    Meta --> CSF
    Meta --> DCF
    Meta --> CSrcF
    KCF --> KC
    CSF --> CSC
    DCF --> DC
    CSrcF --> CSrc
    KC --> CCGF
    CSC --> CCGF
    DC --> CCGF
    CSrc --> CCGF
    CCGF --> CC
    CC --> CPF
    Meta --> CPF
    CPF --> Proxy

相关页面

基于 Apache License 2.0 发布。