@CacheConfig当前类中所有缓存方法详解
@CacheConfig当前类中所有缓存方法详解
在 Spring Cache 抽象中,@CacheConfig
是一个类级别注解,用于为当前类中的所有缓存方法(如 @Cacheable
、@CachePut
、@CacheEvict
)提供默认配置。其核心作用是避免在每个方法上重复声明相同的缓存参数,提升代码简洁性和可维护性。
一、核心属性与应用场景
@CacheConfig
支持以下核心属性,用于定义类级别缓存的默认行为:
属性 | 类型 | 是否必填 | 说明 |
---|---|---|---|
cacheNames | String[] | 否 | 缓存名称的默认值(逗号分隔)。若方法注解未显式指定 value /cacheNames ,则使用此配置。 |
keyGenerator | String | 否 | 键生成器的 Bean 名称(默认使用 SimpleKeyGenerator )。 |
cacheManager | String | 否 | 缓存管理器的 Bean 名称(默认使用全局配置的 cacheManager )。 |
keyPrefix | String | 否 | 缓存键的前缀(Spring 4.3+ 支持,优先级高于 keyGenerator 中的默认前缀逻辑)。 |
condition | String | 否 | 类级别缓存方法的全局条件(SpEL 表达式,仅当方法满足条件时生效)。 |
unless | String | 否 | 类级别缓存方法的全局排除条件(SpEL 表达式,满足条件时不缓存结果)。 |
二、典型使用场景
@CacheConfig
适用于同一类中多个缓存方法需要共享相同配置的场景,例如:
- 同一类中所有缓存操作使用相同的缓存名称(如
userCache
)。 - 同一类中所有缓存方法使用自定义的键生成策略。
- 同一类中所有缓存方法需要统一的缓存管理器(如切换不同缓存实现)。
三、具体用法示例
示例 1:统一缓存名称
假设一个 UserService
类中所有缓存方法都使用 userCache
作为缓存名称,可通过 @CacheConfig(cacheNames = "userCache")
统一声明,避免每个方法重复写 value = "userCache"
。
@Service
@CacheConfig(cacheNames = "userCache") // 类级别统一缓存名称
public class UserService {// 方法 1:使用类级别的 cacheNames(无需显式声明 value)@Cacheable(key = "#userId")public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}// 方法 2:显式声明 cacheNames 会覆盖类级别配置(可选)@Cacheable(value = "profileCache", key = "#userId")public UserProfile getUserProfile(Long userId) {return profileRepository.findById(userId).orElse(null);}
}
示例 2:自定义键生成器
若需要为类中所有缓存方法使用自定义的键生成逻辑(如拼接多个参数),可通过 keyGenerator
指定自定义的键生成器 Bean。
步骤 1:定义自定义键生成器
@Component("customKeyGenerator")
public class CustomKeyGenerator implements KeyGenerator {@Overridepublic Object generate(Object target, Method method, Object... params) {// 自定义键格式:类名::方法名::参数1::参数2...return String.format("%s::%s::%s", target.getClass().getSimpleName(), method.getName(), Arrays.toString(params));}
}
步骤 2:在类上通过 @CacheConfig
引用
@Service
@CacheConfig(cacheNames = "userCache",keyGenerator = "customKeyGenerator" // 使用自定义键生成器
)
public class UserService {@Cacheablepublic User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}@Cacheablepublic User updateUser(Long userId, User newUser) {return userRepository.save(newUser);}
}
此时,两个方法的缓存键会自动生成为:
getUserById::[123]
(假设userId=123
)updateUser::[123, User{id=123,...}]
示例 3:统一缓存管理器
若应用需要为不同缓存类型(如本地缓存和分布式缓存)配置不同的缓存管理器,可通过 cacheManager
指定类级别的缓存管理器。
步骤 1:配置多个缓存管理器
@Configuration
public class CacheConfig {// 本地缓存管理器(Caffeine)@Beanpublic CacheManager caffeineCacheManager() {CaffeineCacheManager manager = new CaffeineCacheManager();manager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES));return manager;}// 分布式缓存管理器(Redis)@Beanpublic CacheManager redisCacheManager(RedisConnectionFactory factory) {RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));return RedisCacheManager.builder(factory).cacheDefaults(config).build();}
}
步骤 2:在类上指定缓存管理器
@Service
@CacheConfig(cacheManager = "redisCacheManager") // 使用 Redis 缓存管理器
public class UserService {@Cacheable(key = "#userId")public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}
}
示例 4:全局条件与排除条件
通过 condition
和 unless
可以为类中所有缓存方法设置全局生效条件。
@Service
@CacheConfig(cacheNames = "userCache",condition = "#userId != null", // 仅当 userId 非空时缓存unless = "#result == null" // 结果为 null 时不缓存
)
public class UserService {@Cacheable(key = "#userId")public User getUserById(Long userId) {return userRepository.findById(userId).orElse(null);}
}
此时,若 userId
为 null
或查询结果为 null
,则不会触发缓存操作。
四、注意事项
作用范围限制
@CacheConfig
仅对当前类中声明的缓存方法(@Cacheable
、@CachePut
、@CacheEvict
)有效,对子类或兄弟类的方法无影响。方法级注解优先级更高
若方法级别的缓存注解(如@Cacheable(value = "profileCache")
)显式声明了某个属性(如value
),则方法级配置会覆盖类级别的默认配置。属性冲突处理
cacheNames
:方法级未声明时使用类级别;方法级声明时覆盖类级别。keyGenerator
/cacheManager
:方法级未声明时使用类级别;方法级声明时覆盖类级别。condition
/unless
:类级别条件与方法级别条件为逻辑与(AND)关系(即两者都满足时才生效)。
适用 Spring 版本
@CacheConfig
自 Spring 3.2 引入,所有 Spring Boot 1.x 及以上版本均支持。
五、总结
@CacheConfig
是 Spring Cache 中用于类级别缓存配置复用的核心注解,通过它可以统一管理同一类中所有缓存方法的公共参数(如缓存名称、键生成策略、缓存管理器等),显著减少重复代码,提升可维护性。结合方法级注解的灵活性,能够高效应对不同业务场景的缓存需求。