@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 {
@Override
public 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 {
@Cacheable
public User getUserById(Long userId) {
return userRepository.findById(userId).orElse(null);
}
@Cacheable
public 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)
@Bean
public CacheManager caffeineCacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES));
return manager;
}
// 分布式缓存管理器(Redis)
@Bean
public 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 中用于类级别缓存配置复用的核心注解,通过它可以统一管理同一类中所有缓存方法的公共参数(如缓存名称、键生成策略、缓存管理器等),显著减少重复代码,提升可维护性。结合方法级注解的灵活性,能够高效应对不同业务场景的缓存需求。