Skip to content

Spring Integration API ​

CoCache provides deep integration with the Spring Framework through the cocache-spring, cocache-spring-cache, and cocache-spring-boot-starter modules. This page documents all Spring-specific components.

Module Overview ​

mermaid
graph TB
    subgraph Starter["cocache-spring-boot-starter"]
        style Starter fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        Auto["CoCacheAutoConfiguration"]
        Props["CoCacheProperties"]
        Cond["@ConditionalOnCoCacheEnabled"]
        EP["CoCacheEndpoint"]
        CEP["CoCacheClientEndpoint"]
        EPAC["CoCacheEndpointAutoConfiguration"]
    end

    subgraph SpringCache["cocache-spring-cache"]
        style SpringCache fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        CCM["CoCacheManager"]
        CSC["CoSpringCache"]
    end

    subgraph Spring["cocache-spring"]
        style Spring fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        EC["EnableCoCache"]
        REG["EnableCoCacheRegistrar"]
        SCF["SpringCacheFactory"]
        ACF["AbstractCacheFactory"]
        CPFB["CacheProxyFactoryBean"]
        JCPFB["JoinCacheProxyFactoryBean"]
        SCSC["SpringClientSideCacheFactory"]
        SKCF["SpringKeyConverterFactory"]
        SCSrcF["SpringCacheSourceFactory"]
        SJKEF["SpringJoinKeyExtractorFactory"]
    end

    subgraph Core["cocache-core"]
        style Core fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        CPF["DefaultCacheProxyFactory"]
        CCF["DefaultCoherentCacheFactory"]
    end

    Auto --> SCF
    Auto --> CPF
    Auto --> CCF
    Auto --> CCM
    REG --> CPFB
    REG --> JCPFB
    CPFB --> CPF
    JCPFB --> JCPF["JoinCacheProxyFactory"]
    CCM --> CSC
    SCF --> ACF
    SCSC --> ACF
    SKCF --> ACF
    SCSrcF --> ACF

Factory Beans ​

CacheProxyFactoryBean ​

Spring FactoryBean that creates proxy-based cache instances for @CoCache-annotated interfaces.

AspectDetailSource
ImplementsFactoryBean<Cache<Any, Any>>, ApplicationContextAware--
Constructor(cacheMetadata: CoCacheMetadata)--
Source File--CacheProxyFactoryBean.kt:23
MethodReturnsDescription
getObject()Cache<Any, Any>Retrieves CacheProxyFactory from the application context and calls create(cacheMetadata)
getObjectType()Class<*>Returns the cache interface class (cacheMetadata.proxyInterface.java)

JoinCacheProxyFactoryBean ​

Spring FactoryBean that creates proxy-based join cache instances for @JoinCacheable-annotated interfaces.

AspectDetailSource
ImplementsFactoryBean<JoinCache<Any, Any, Any, Any>>, ApplicationContextAware--
Constructor(cacheMetadata: JoinCacheMetadata)--
Source File--JoinCacheProxyFactoryBean.kt:23
MethodReturnsDescription
getObject()JoinCache<Any, Any, Any, Any>Retrieves JoinCacheProxyFactory from the application context and calls create(cacheMetadata)
getObjectType()Class<*>Returns the join cache interface class

AbstractCacheFactory Pattern ​

The AbstractCacheFactory provides a template method pattern for creating cache components from Spring beans, with a named-bean-first lookup strategy and type-based fallback.

AspectDetailSource
Packageme.ahoo.cache.spring--
Source File--AbstractCacheFactory.kt:21

Bean Resolution Strategy ​

mermaid
flowchart TB
    subgraph Strategy["Bean Resolution Strategy"]
        style Strategy fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        Start["resolve(cacheMetadata)"]
        NameLookup["Look up by name:<br>{cacheName}{suffix}"]
        NameFound{"Bean found?"}
        TypeLookup["resolveByType()<br>(CacheSource only)"]
        TypeFound{"Unique bean?"}
        Fallback["Use default fallback"]
        Return["Return bean"]

        Start --> NameLookup
        NameLookup --> NameFound
        NameFound -- "yes" --> Return
        NameFound -- "no" --> TypeLookup
        TypeLookup --> TypeFound
        TypeFound -- "yes" --> Return
        TypeFound -- "no" --> Fallback
        Fallback --> Return
    end

Abstract Methods ​

MethodSignatureDescription
suffixabstract val suffix: StringBean name suffix for this factory type
resolveByTypeopen fun resolveByType(cacheMetadata: CoCacheMetadata): Any?Optional unique-type lookup (only for stateless components; default null)
fallbackabstract fun fallback(cacheMetadata: CoCacheMetadata): AnyDefault component when no Spring bean is found

Spring Factory Implementations ​

All Spring factory implementations extend AbstractCacheFactory: named bean first, then (stateless components only) a unique bean by type, then the default.

SpringClientSideCacheFactory ​

AspectDetailSource
ImplementsClientSideCacheFactory, AbstractCacheFactory--
Bean Name Suffix.ClientSideCache--
FallbackDefaultClientSideCacheFactory.create() (bounded Caffeine per @CaffeineCache)--
Source File--SpringClientSideCacheFactory.kt:25

SpringKeyConverterFactory ​

AspectDetailSource
ImplementsKeyConverterFactory, AbstractCacheFactory--
Bean Name Suffix.KeyConverter--
FallbackExpKeyConverter if keyExpression is set, otherwise ToStringKeyConverter with computed prefix--
Source File--SpringKeyConverterFactory.kt:27

Key prefixes and expressions resolve Spring placeholders (${...}). Converters are never shared by type: two caches with the same key type would otherwise share one prefix and collide.

SpringCacheSourceFactory ​

AspectDetailSource
ImplementsCacheSourceFactory, AbstractCacheFactory--
Bean Name Suffix.CacheSource--
Type fallbackunique CacheSource<K, V> bean--
FallbackCacheSource.noOp()--
Source File--SpringCacheSourceFactory.kt:24

SpringJoinKeyExtractorFactory ​

AspectDetailSource
ImplementsJoinKeyExtractorFactory--
Bean Name Suffix.JoinKeyExtractor--
FallbackUses joinKeyExpression SpEL if set, otherwise type-based bean lookup--
Source File--SpringJoinKeyExtractorFactory.kt:24

SpringCacheFactory ​

The CacheFactory implementation that retrieves cache beans from the Spring BeanFactory.

AspectDetailSource
ImplementsCacheFactory--
Constructor(beanFactory: ListableBeanFactory)--
Source File--SpringCacheFactory.kt:24
MethodDescription
cachesReturns all Cache beans from the application context via getBeansOfType(Cache::class.java)
getCache(cacheName, cacheType)Retrieves a cache bean by name and type
getCache(keyType, valueType)Retrieves a cache bean by generic key/value types using ResolvableType

Bean Naming Conventions ​

CoCache uses a consistent {cacheName}.{Suffix} naming pattern for optional customization beans. Register a Spring bean with the matching name to override the default.

Bean Name PatternFactoryPurposeDefault Behavior
{cacheName}.ClientSideCacheSpringClientSideCacheFactoryL2 local cacheDefaultClientSideCacheFactory.create()
{cacheName}.DistributedCacheRedisDistributedCacheFactoryL1 distributed cacheRedis-backed RedisDistributedCache
{cacheName}.CacheSourceSpringCacheSourceFactoryL0 data sourceCacheSource.noOp()
{cacheName}.KeyConverterSpringKeyConverterFactoryKey conversionToStringKeyConverter or ExpKeyConverter
{cacheName}.JoinKeyExtractorSpringJoinKeyExtractorFactoryJoin key extractionSpEL expression or type-based bean
{cacheName}.CacheMetadataEnableCoCacheRegistrarParsed annotation metadataAuto-generated

Customization Example ​

To provide a custom ClientSideCache for a specific cache:

kotlin
@Configuration
class CustomCacheConfig {

    @Bean("user-cache.ClientSideCache")
    fun userClientSideCache(): ClientSideCache<User> {
        return CaffeineClientSideCache.build(maximumSize = 20_000, expireAfterAccess = Duration.ofMinutes(10))
    }

    @Bean("user-cache.CacheSource")
    fun userCacheSource(userRepository: UserRepository): CacheSource<String, User> {
        return CacheSource { key ->
            userRepository.findById(key).map { CacheValue.of(it, TtlAt.at(3600)) }.orElse(null)
        }
    }
}

CoCacheManager ​

Bridge between CoCache and Spring's CacheManager abstraction, enabling @Cacheable and other Spring Cache annotations.

AspectDetailSource
ExtendsAbstractCacheManager--
Constructor(cacheFactory: CacheFactory)--
Source File--CoCacheManager.kt:21
MethodReturnsDescription
loadCaches()Collection<SpringCache>Wraps all registered CoCache instances as CoSpringCache adapters
getMissingCache(name)SpringCache?Looks up a CoCache by name and wraps it if found; returns null otherwise

CoCacheManager Flow ​

mermaid
sequenceDiagram
autonumber
    participant SC as Spring Container
    participant CCM as CoCacheManager
    participant CF as CacheFactory
    participant CSW as CoSpringCache

    SC->>CCM: getCache("user-cache")
    CCM->>CCM: Check internal cache map
    alt Cache not found internally
        CCM->>CF: getCache("user-cache")
        CF-->>CCM: Cache instance
        CCM->>CSW: new CoSpringCache("user-cache", cache)
        CCM->>CCM: Register in internal map
    end
    CCM-->>SC: CoSpringCache wrapper

CoSpringCache ​

Adapter that wraps a CoCache Cache instance as a Spring Cache implementation.

AspectDetailSource
ImplementsNamedCache, SpringCache, CacheDelegated<Cache<Any, Any?>>--
Constructor(cacheName: String, delegate: Cache<Any, Any?>, asyncExecutor: Executor)--
Source File--CoSpringCache.kt:27
MethodSpring InterfaceDescription
getName()Cache.getName()Returns the cache name
getNativeCache()Cache.getNativeCache()Returns the underlying CoCache instance
get(key)Cache.get(key)SimpleValueWrapper(value) on hit; null for absent, expired, or negative-cache entries
get(key, type)Cache.get(key, type)Returns the value cast to the specified type
get(key, valueLoader)Cache.get(key, valueLoader)Loads at most once per key concurrently (@Cacheable(sync = true)), then stores it
put(key, value)Cache.put(key, value)Delegates to delegate.set(key, value)
evict(key)Cache.evict(key)Delegates to delegate.evict(key)
clear()Cache.clear()Clears the ClientSideCache (if CoherentCache, clears L2 only)
retrieve(key)Cache.retrieve(key)Async lookup on the dedicated asyncExecutor (not the ForkJoin common pool)
retrieve(key, valueLoader)Cache.retrieve(key, valueLoader)Async get with CompletableFuture composition

Using with @Cacheable ​

Once CoCacheManager is registered, standard Spring Cache annotations work seamlessly:

kotlin
@Service
class UserService(
    private val userRepository: UserRepository
) {
    @Cacheable(cacheNames = ["user-cache"], key = "#userId")
    fun getUser(userId: String): User {
        return userRepository.findById(userId).orElseThrow()
    }

    @CacheEvict(cacheNames = ["user-cache"], key = "#userId")
    fun deleteUser(userId: String) {
        userRepository.deleteById(userId)
    }
}

EnableCoCacheRegistrar ​

The registrar that processes @EnableCoCache and registers CacheProxyFactoryBean / JoinCacheProxyFactoryBean definitions.

AspectDetailSource
ImplementsImportBeanDefinitionRegistrar--
Source File--EnableCoCacheRegistrar.kt:31

Registration Logic ​

StepAction
1Resolve cache types from @EnableCoCache.caches attribute
2Split into standard caches (not extending JoinCache) and join caches
3For standard caches: parse CoCacheMetadata, register metadata bean + CacheProxyFactoryBean (marked as primary)
4For join caches: parse JoinCacheMetadata, register JoinCacheProxyFactoryBean (marked as primary)

CoCacheAutoConfiguration ​

Spring Boot auto-configuration class that wires up all CoCache components.

AspectDetailSource
Condition@ConditionalOnCoCacheEnabled, @AutoConfiguration(after = [DataRedisAutoConfiguration::class])--
Source File--CoCacheAutoConfiguration.kt:66

Registered Beans ​

Bean NameTypeConditionDescription
defaultHostClientIdGeneratorClientIdGeneratorNo ClientIdGenerator or HostAddressSupplier bean existsUses host address as client ID
cacheFactoryCacheFactoryNo existing beanSpringCacheFactory backed by ListableBeanFactory
coCacheManagerCoCacheManagerAlwaysSpring Cache bridge
cocacheRedisMessageListenerContainerRedisMessageListenerContainerRedisConnectionFactory availableRedis pub/sub listener for eviction events
cacheEvictedEventBusCacheEvictedEventBusNo existing beanRedisCacheEvictedEventBus
coherentCacheFactoryCoherentCacheFactoryNo existing beanDefaultCoherentCacheFactory
cacheSourceFactoryCacheSourceFactoryNo existing beanSpringCacheSourceFactory
clientSideCacheFactoryClientSideCacheFactoryNo existing beanSpringClientSideCacheFactory
distributedCacheFactoryDistributedCacheFactoryNo existing beanRedisDistributedCacheFactory
keyConverterFactoryKeyConverterFactoryNo existing beanSpringKeyConverterFactory
cacheProxyFactoryCacheProxyFactoryNo existing beanDefaultCacheProxyFactory
joinKeyExtractorFactoryJoinKeyExtractorFactoryNo existing beanSpringJoinKeyExtractorFactory
joinCacheProxyFactoryJoinCacheProxyFactoryNo existing beanDefaultJoinCacheProxyFactory

Auto-Configuration Dependency Graph ​

mermaid
graph TB
    subgraph Redis["Redis Auto-Configuration"]
        style Redis fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        DRA["DataRedisAutoConfiguration"]
        RT["StringRedisTemplate"]
        RCF["RedisConnectionFactory"]
    end

    subgraph CoCache["CoCacheAutoConfiguration"]
        style CoCache fill:#161b22,stroke:#6d5dfc,color:#e6edf3
        CCG["ClientIdGenerator"]
        CEV["CacheEvictedEventBus"]
        CCF["CoherentCacheFactory"]
        CPF["CacheProxyFactory"]
        CSrcF["CacheSourceFactory"]
        CSF["ClientSideCacheFactory"]
        DCF["DistributedCacheFactory"]
        KCF["KeyConverterFactory"]
        SCF["CacheFactory"]
        CCM["CoCacheManager"]
        JKEF["JoinKeyExtractorFactory"]
        JCPF["JoinCacheProxyFactory"]
    end

    RCF --> CEV
    RT --> CEV
    DRA --> CoCache
    CCG --> CPF
    CCF --> CPF
    CSrcF --> CPF
    CSF --> CPF
    DCF --> CPF
    KCF --> CPF
    SCF --> CCM

Released under the Apache License 2.0.