Skip to content

CoCache API Overview

CoCache provides a Level 2 Distributed Coherence Cache Framework for Java/Kotlin applications. The API is organized across multiple modules, each responsible for a distinct layer of the caching architecture.

Module Organization

The API surface is spread across the following modules, ordered from low-level to high-level:

ModuleArtifactPurposeSource
cocache-apiCore interfaces and annotationsDefines Cache, CacheValue, ClientSideCache, CacheSource, JoinCache, and all cache annotationscocache-api/src/main/kotlin/me/ahoo/cache/api
cocache-coreDefault implementationsProvides DefaultCoherentCache, proxy-based caching, key converters, event bus, key filterscocache-core/src/main/kotlin/me/ahoo/cache
cocache-springSpring Framework integrationFactory beans, @EnableCoCache, Spring-aware factories for client-side/distributed cachescocache-spring/src/main/kotlin/me/ahoo/cache/spring
cocache-spring-redisRedis distributed cacheRedisDistributedCache, RedisCacheEvictedEventBus, RedisDistributedCacheFactorycocache-spring-redis/src/main/kotlin/me/ahoo/cache/spring/redis
cocache-spring-cacheSpring Cache bridgeCoCacheManager, CoSpringCache adapters for Spring's CacheManager abstractioncocache-spring-cache/src/main/kotlin/me/ahoo/cache/spring/cache
cocache-spring-boot-starterSpring Boot auto-configurationCoCacheAutoConfiguration, actuator endpoints, properties bindingcocache-spring-boot-starter/src/main/kotlin/me/ahoo/cache/spring/boot/starter

Interface Hierarchy

The CoCache API is built on a layered interface hierarchy. The following diagram shows the core type relationships:

mermaid
classDiagram
    direction TB

    class Cache~K,V~ {
        <<interface>>
    }
    class CacheGetter~K,V~ {
        <<interface>>
        +getCache(key: K) CacheValue~V~?
        +get(key: K) V?
        +getTtlAt(key: K) Long?
    }
    class CacheSetter~K,V~ {
        <<interface>>
        +set(key: K, ttlAt: Long, value: V)
        +set(key: K, value: V)
        +setCache(key: K, value: CacheValue~V~)
        +evict(key: K)
    }
    class ComputedCache~K,V~ {
        <<interface>>
        +ttl: Long
        +ttlAmplitude: Long
    }
    class NamedCache {
        <<interface>>
        +cacheName: String
    }
    class DistributedClientId {
        <<interface>>
        +clientId: String
    }
    class TtlConfiguration {
        <<interface>>
        +ttl: Long
        +ttlAmplitude: Long
    }
    class CacheEvictedSubscriber {
        <<interface>>
        +onEvicted(event: CacheEvictedEvent)
    }
    class CoherentCache~K,V~ {
        <<interface>>
        +cacheEvictedEventBus: CacheEvictedEventBus
        +clientSideCache: ClientSideCache~V~
        +distributedCache: DistributedCache~V~
        +keyFilter: KeyFilter
        +keyConverter: KeyConverter~K~
        +cacheSource: CacheSource~K,V~
    }

    Cache <|-- CacheGetter
    Cache <|-- CacheSetter
    Cache <|-- ComputedCache
    ComputedCache ..|> TtlConfiguration
    CoherentCache ..|> ComputedCache
    CoherentCache ..|> DistributedClientId
    CoherentCache ..|> NamedCache
    CoherentCache ..|> CacheEvictedSubscriber

    style Cache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CacheGetter fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CacheSetter fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style ComputedCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style NamedCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style DistributedClientId fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style TtlConfiguration fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CacheEvictedSubscriber fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CoherentCache fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

Cache Layer Architecture

CoCache implements a three-tier cache architecture with L2 (client-side), L1 (distributed), and L0 (data source):

mermaid
graph TB
    subgraph Client["Client Instance"]
        style Client fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        App["Application Code"]
        Proxy["Cache Proxy<br>(Dynamic Proxy)"]
        L2["L2: ClientSideCache<br>(Guava / Caffeine / Map)"]
    end

    subgraph Distributed["Shared Layer"]
        style Distributed fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        L1["L1: DistributedCache<br>(Redis)"]
        EventBus["CacheEvictedEventBus<br>(Redis Pub/Sub)"]
    end

    subgraph DataSource["Data Layer"]
        style DataSource fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        L0["L0: CacheSource<br>(Database / API)"]
    end

    App --> Proxy
    Proxy --> L2
    L2 -- "miss" --> L1
    L1 -- "miss" --> L0
    L0 -- "loaded" --> L1
    L1 -- "cached" --> L2
    Proxy -- "evict" --> L2
    Proxy -- "evict" --> L1
    L1 -- "evict event" --> EventBus
    EventBus -- "invalidate" --> L2

Key Packages

cocache-api Packages

PackageDescriptionKey Types
me.ahoo.cache.apiCore cache abstractionsCache, CacheGetter, CacheSetter, CacheValue, TtlAt, NamedCache
me.ahoo.cache.api.clientClient-side cache interfaceClientSideCache
me.ahoo.cache.api.sourceData source interfaceCacheSource, NoOpCacheSource
me.ahoo.cache.api.joinJoin cache abstractionsJoinCache, JoinValue, JoinKeyExtractor
me.ahoo.cache.api.annotationDeclarative cache annotations@CoCache, @GuavaCache, @CaffeineCache, @JoinCacheable

cocache-core Packages

PackageDescriptionKey Types
me.ahoo.cacheCore implementations and interfacesComputedCache, DefaultCacheValue, MissingGuard, KeyFilter, TtlConfiguration
me.ahoo.cache.consistencyCache coherence engineCoherentCache, DefaultCoherentCache, CacheEvictedEventBus, CacheEvictedEvent, CoherentCacheFactory
me.ahoo.cache.proxyDynamic proxy-based cachingCacheProxyFactory, DefaultCacheProxyFactory, CoCacheInvocationHandler, CoCacheProxy
me.ahoo.cache.clientClient-side cache implementationsMapClientSideCache, GuavaClientSideCache, CaffeineClientSideCache, ClientSideCacheFactory
me.ahoo.cache.distributedDistributed cache abstractionsDistributedCache, DistributedClientId, DistributedCacheFactory
me.ahoo.cache.converterKey conversion utilitiesKeyConverter, ToStringKeyConverter, ExpKeyConverter, KeyConverterFactory
me.ahoo.cache.filterCache key filtersBloomKeyFilter, NoOpKeyFilter
me.ahoo.cache.sourceCache source factoriesCacheSourceFactory
me.ahoo.cache.joinJoin cache implementationSimpleJoinCache, DefaultJoinValue, ExpJoinKeyExtractor, JoinKeyExtractorFactory
me.ahoo.cache.annotationMetadata parsersCoCacheMetadata, CoCacheMetadataParser, JoinCacheMetadata, JoinCacheMetadataParser

Dynamic Proxy Architecture

CoCache uses JDK dynamic proxies to implement cache interfaces. The proxy intercepts all method calls and delegates to the underlying CoherentCache:

mermaid
sequenceDiagram
autonumber
    participant App as Application
    participant Proxy as Cache Proxy<br>(JDK Dynamic Proxy)
    participant Handler as CoCacheInvocationHandler
    participant Coherent as DefaultCoherentCache
    participant L2 as ClientSideCache
    participant L1 as DistributedCache
    participant L0 as CacheSource
    participant Bus as CacheEvictedEventBus

    App->>Proxy: cache.get(key)
    Proxy->>Handler: invoke(proxy, method, args)
    Handler->>Coherent: getCache(key)
    Coherent->>L2: getCache(cacheKey)
    alt L2 Hit
        L2-->>Coherent: CacheValue
    else L2 Miss
        Coherent->>L1: getCache(cacheKey)
        alt L1 Hit
            L1-->>Coherent: CacheValue
            Coherent->>L2: setCache(cacheKey, value)
        else L1 Miss
            Coherent->>L0: loadCacheValue(key)
            L0-->>Coherent: CacheValue
            Coherent->>L2: setCache(cacheKey, value)
            Coherent->>L1: setCache(cacheKey, value)
            Coherent->>Bus: publish(CacheEvictedEvent)
        end
    end
    Coherent-->>Handler: CacheValue
    Handler-->>Proxy: value
    Proxy-->>App: value

Cache Eviction Flow

When a cache entry is evicted, the event is propagated across all client instances via the event bus:

mermaid
graph LR
    subgraph InstanceA["Instance A"]
        style InstanceA fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        A_Proxy["Cache Proxy"]
        A_L2["L2 Cache"]
        A_L1["L1 Cache"]
    end

    subgraph EventBus["Event Bus (Redis Pub/Sub)"]
        style EventBus fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        Bus["CacheEvictedEventBus"]
    end

    subgraph InstanceB["Instance B"]
        style InstanceB fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        B_L2["L2 Cache"]
        B_Coherent["CoherentCache"]
    end

    A_Proxy -->|"evict(key)"| A_L2
    A_Proxy -->|"evict(key)"| A_L1
    A_L1 -->|"publish(event)"| Bus
    Bus -->|"onEvicted(event)"| B_Coherent
    B_Coherent -->|"evict(key)"| B_L2

Factory Pattern

CoCache uses a factory pattern extensively to create cache components. All factories accept a CoCacheMetadata (parsed from annotations) and produce the corresponding cache component:

mermaid
classDiagram
    direction TB

    class CacheProxyFactory {
        <<interface>>
        +create(cacheMetadata: CoCacheMetadata) CACHE
    }
    class CoherentCacheFactory {
        <<interface>>
        +create(cacheConfig: CoherentCacheConfiguration) CoherentCache
    }
    class ClientSideCacheFactory {
        <<interface>>
        +create(cacheMetadata: CoCacheMetadata) ClientSideCache
    }
    class DistributedCacheFactory {
        <<interface>>
        +create(cacheMetadata: CoCacheMetadata) DistributedCache
    }
    class CacheSourceFactory {
        <<interface>>
        +create(cacheMetadata: CoCacheMetadata) CacheSource
    }
    class KeyConverterFactory {
        <<interface>>
        +create(cacheMetadata: CoCacheMetadata) KeyConverter
    }
    class JoinKeyExtractorFactory {
        <<interface>>
        +create(cacheMetadata: JoinCacheMetadata) JoinKeyExtractor
    }
    class JoinCacheProxyFactory {
        <<interface>>
        +create(cacheMetadata: JoinCacheMetadata) CACHE
    }

    class DefaultCacheProxyFactory {
        +coherentCacheFactory
        +clientIdGenerator
        +clientSideCacheFactory
        +distributedCacheFactory
        +cacheSourceFactory
        +keyConverterFactory
    }
    class DefaultCoherentCacheFactory {
        +cacheEvictedEventBus
    }

    CacheProxyFactory <|.. DefaultCacheProxyFactory
    CoherentCacheFactory <|.. DefaultCoherentCacheFactory
    DefaultCacheProxyFactory --> CoherentCacheFactory
    DefaultCacheProxyFactory --> ClientSideCacheFactory
    DefaultCacheProxyFactory --> DistributedCacheFactory
    DefaultCacheProxyFactory --> CacheSourceFactory
    DefaultCacheProxyFactory --> KeyConverterFactory

    style CacheProxyFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CoherentCacheFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style ClientSideCacheFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style DistributedCacheFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style CacheSourceFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style KeyConverterFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style JoinKeyExtractorFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style JoinCacheProxyFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style DefaultCacheProxyFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3
    style DefaultCoherentCacheFactory fill:#2d333b,stroke:#6d5dfc,color:#e6edf3

Released under the Apache License 2.0.