# How to Use SpEL Expressions for Dynamic Cache Key Generation in @CoCache

> Generate dynamic cache keys in @CoCache with SpEL expressions. Learn how to use the keyExpression attribute to customize caching based on method arguments and Spring beans.

- Repository: [Ahoo Wang/cocache](https://github.com/ahoo-wang/cocache)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Use the `keyExpression` attribute in the `@CoCache` annotation to define Spring Expression Language (SpEL) strings that dynamically generate cache keys from method arguments, Spring beans, or computed values.**

The `@CoCache` annotation from the [ahoo-wang/cocache](https://github.com/ahoo-wang/cocache) repository provides the foundation for automatic cache proxy generation in Spring applications. While static configuration via `keyPrefix` offers basic namespacing, the `keyExpression` attribute unlocks dynamic key generation by evaluating SpEL expressions against method parameters at runtime.

## Understanding the @CoCache Key Generation Pipeline

When a method annotated with `@CoCache` is invoked, the CoCache infrastructure constructs the final cache key through a three-step resolution process.

### Static Prefix Handling

First, if the `keyPrefix` attribute is set on the annotation, CoCache prepends this static string to the generated key. This parameter is defined in [[`CoCache.kt`](https://github.com/ahoo-wang/cocache/blob/main/CoCache.kt)](https://github.com/ahoo-wang/cocache/blob/main/cocache-api/src/main/kotlin/me/ahoo/cache/api/annotation/CoCache.kt#L30) and provides a namespace-like separation for different cache instances.

### Dynamic SpEL Evaluation

If `keyExpression` contains a non-blank SpEL string, the framework parses it using Spring's `SpelExpressionParser` and evaluates it against the method's execution context. The [`SpringKeyConverterFactory`](https://github.com/ahoo-wang/cocache/blob/main/cocache-spring/src/main/kotlin/me/ahoo/cache/spring/converter/SpringKeyConverterFactory.kt#L57-L58) detects this configuration and instantiates an `ExpKeyConverter` to handle the evaluation. The resulting object is converted to a `String` and forms the dynamic portion of the cache key.

### Default Fallback Behavior

When `keyExpression` is empty or omitted, CoCache delegates to the [`DefaultKeyConverterFactory`](https://github.com/ahoo-wang/cocache/blob/main/cocache-core/src/main/kotlin/me/ahoo/cache/converter/DefaultKeyConverterFactory.kt#L24-L25). This fallback implementation concatenates the method name with serialized parameter values, generating deterministic but less flexible keys.

## Configuring SpEL Expressions in @CoCache

The `keyExpression` attribute accepts any valid SpEL string. Within these expressions, you can reference method arguments by name (e.g., `#userId`), access the root object (`#root`), call methods on parameters, or invoke Spring beans using the `@beanName` syntax.

```kotlin
@CoCache(keyExpression = "#{#user.id}_#{#operation}")
interface UserActivityCache : Cache<String, Activity>

```

Composite keys combine multiple arguments into a single string, while bean references allow external key generation logic to remain decoupled from the cache interface.

## Practical SpEL Expression Examples

The following patterns demonstrate common use cases for dynamic cache key generation in CoCache.

### Accessing Method Arguments

Reference individual parameters directly to create targeted cache keys.

```kotlin
// Uses the first parameter as the key
@CoCache(keyExpression = "#{#root}")
interface UserCache : Cache<String, User>

// Combines multiple parameters with a delimiter
@CoCache(keyExpression = "'user:' + #userId + ':' + #tenantId")
interface TenantUserCache : Cache<String, User>

```

### Invoking Spring Beans

Delegate complex key generation to dedicated Spring components.

```kotlin
@CoCache(keyExpression = "#{@uuidGenerator.nextId()}")
interface SessionCache : Cache<String, Session>

```

### Combining Prefix and Expression

Use `keyPrefix` for static namespaces alongside dynamic expressions.

```kotlin
@CoCache(keyPrefix = "order:", keyExpression = "#orderId")
interface OrderCache : Cache<String, Order>

```

## How SpEL Evaluation Works Under the Hood

The CoCache framework processes SpEL expressions through a dedicated conversion pipeline. When [[`CoCacheMetadataParser.kt`](https://github.com/ahoo-wang/cocache/blob/main/CoCacheMetadataParser.kt)](https://github.com/ahoo-wang/cocache/blob/main/cocache-core/src/main/kotlin/me/ahoo/cache/annotation/CoCacheMetadataParser.kt) parses the annotation, it extracts the `keyExpression` string into `CoCacheMetadata`. During cache operation execution, [[`ExpKeyConverter.kt`](https://github.com/ahoo-wang/cocache/blob/main/ExpKeyConverter.kt)](https://github.com/ahoo-wang/cocache/blob/main/cocache-core/src/main/kotlin/me/ahoo/cache/converter/ExpKeyConverter.kt) evaluates the parsed expression against the method's argument array, converting the result to a string representation. This evaluated string is then optionally prefixed and wrapped in a `CacheKey` object for the underlying cache provider (Caffeine, Guava, or Redis).

## Summary

- **Use `keyExpression`** in `@CoCache` to define SpEL strings that generate dynamic cache keys at runtime.
- **Reference method arguments** using `#paramName` syntax or `#root` for the first argument.
- **Access Spring beans** within expressions using `@beanName.method()` syntax for complex key generation logic.
- **Combine with `keyPrefix`** to maintain static namespaces while allowing dynamic key components.
- **Fallback behavior** automatically uses method name concatenation when `keyExpression` is omitted.

## Frequently Asked Questions

### What is the default cache key strategy when keyExpression is not specified?

When `keyExpression` is empty, CoCache uses the `DefaultKeyConverterFactory` to generate keys by concatenating the method name with its parameter values. This produces deterministic keys based on the method signature and arguments without requiring explicit SpEL configuration.

### Can I access Spring beans inside a SpEL expression for cache keys?

Yes. Use the `@beanName` syntax to reference any Spring bean in the application context. For example, `#{@myKeyGenerator.generate(#id)}` invokes the `generate` method on a bean named `myKeyGenerator`, passing the `id` parameter from the cached method.

### How do I handle null values in SpEL cache key expressions?

Use the null-safe navigation operator `?.` within your SpEL expression. For example, `#{#user?.id}` evaluates to null if `user` is null, rather than throwing an exception. You can also provide default values using the Elvis operator: `#{#user?.id ?: 'anonymous'}`.

### Does the keyPrefix support SpEL expressions or only static strings?

The `keyPrefix` attribute only accepts static strings. For dynamic prefix behavior, omit `keyPrefix` and include the entire key logic within `keyExpression`, such as `"'dynamic:' + #tenant + ':' + #id"`.