Spring Boot 缓存注解与 JCache 提供程序深度集成详解
一、Spring Boot 缓存注解架构设计
1.1 Spring 缓存抽象层架构
// Spring 缓存抽象核心接口
public interface Cache {
String getName(); // 缓存名称
Object get(Object key); // 获取缓存值
void put(Object key, Object value); // 存入缓存
void evict(Object key); // 逐出单个键
void clear(); // 清空缓存
}
// Spring CacheManager 接口
public interface CacheManager {
Cache getCache(String name); // 获取缓存实例
Collection<String> getCacheNames(); // 获取所有缓存名称
}
// Spring JCache 适配器实现
public class JCacheCache implements Cache {
private final javax.cache.Cache<Object, Object> cache;
@Override
public Object get(Object key) {
return this.cache.get(key);
}
@Override
public void put(Object key, Object value) {
this.cache.put(key, value);
}
@Override
public void evict(Object key) {
this.cache.remove(key);
}
}
1.2 注解处理执行流程
// Spring 缓存注解拦截器
@Aspect
@Component
public class CacheAnnotationAspect {
@Around("@annotation(cacheable)")
public Object processCacheable(ProceedingJoinPoint joinPoint,
Cacheable cacheable) throws Throwable {
// 1. 生成缓存键
Object key = generateKey(joinPoint, cacheable.key());
// 2. 尝试从缓存获取
Cache cache = cacheManager.getCache(cacheable.value());
Cache.ValueWrapper cachedValue = cache.get(key);
if (cachedValue != null) {
// 3. 缓存命中,直接返回
return cachedValue.get();
}
// 4. 缓存未命中,执行方法
Object result = joinPoint.proceed();
// 5. 将结果放入缓存
if (result != null) {
cache.put(key, result);
}
return result;
}
}
二、Spring Boot 与 JCache 集成配置
2.1 基础依赖配置
<!– Maven 依赖配置 –>
<dependencies>
<!– Spring Boot 缓存启动器 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!– JCache API (JSR-107) –>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<!– Ehcache 3 实现 –>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<classifier>jakarta</classifier> <!– 针对 Jakarta EE 9+ –>
</dependency>
<!– 或者 Hazelcast 实现 –>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
</dependency>
<!– Spring Boot Ehcache 3 自动配置 –>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-ehcache</artifactId>
</dependency>
</dependencies>
2.2 应用配置文件
# application.yml – 缓存配置
spring:
cache:
type: jcache # 指定使用 JCache 实现
# JCache 特定配置
jcache:
provider: org.ehcache.jsr107.EhcacheCachingProvider # 指定提供程序
config: classpath:ehcache.xml # JCache 配置文件
# 缓存名称配置
cache-names:
– userCache
– productCache
– orderCache
# 通用缓存配置
caffeine:
spec: maximumSize=500,expireAfterAccess=600s
redis:
time-to-live: 600000 # 默认TTL 10分钟
cache-null-values: true
# Ehcache 3 特定配置
ehcache:
config: classpath:ehcache3.xml
# Hazelcast 特定配置
hazelcast:
config: classpath:hazelcast.yaml
cache:
default-time-to-live-seconds: 600
2.3 缓存配置类
@Configuration
@EnableCaching // 启用缓存支持
@AutoConfigureAfter(CacheAutoConfiguration.class)
public class CacheConfiguration {
/**
* 方式1:使用 JCache 标准配置
*/
@Bean
@Primary
public CacheManager cacheManager() {
CachingProvider cachingProvider = Caching.getCachingProvider();
// 从配置文件加载
URI configUri = getClass().getResource("/ehcache.xml").toURI();
// 创建 JCache CacheManager
javax.cache.CacheManager jcacheManager =
cachingProvider.getCacheManager(configUri,
getClass().getClassLoader());
// 包装为 Spring CacheManager
return new JCacheCacheManager(jcacheManager);
}
/**
* 方式2:Ehcache 3 专用配置
*/
@Bean
public CacheManager ehcacheCacheManager() {
// 创建 Ehcache 配置
CacheManagerConfiguration<CacheManager> config =
CacheManagerBuilder.newCacheManagerBuilder()
.withCache("userCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
String.class, User.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(1000, EntryUnit.ENTRIES)
.offheap(100, MemoryUnit.MB)
.build())
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofMinutes(10))))
.withCache("productCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, Product.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(5000, EntryUnit.ENTRIES)
.build())
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(
Duration.ofMinutes(5))))
.build();
// 初始化并返回
return new EhCacheCacheManager(config.build(true));
}
/**
* 方式3:Hazelcast 专用配置
*/
@Bean
public CacheManager hazelcastCacheManager() {
// 创建 Hazelcast 配置
Config config = new Config();
// 添加缓存配置
CacheSimpleConfig userCacheConfig = new CacheSimpleConfig()
.setName("userCache")
.setKeyType(String.class.getName())
.setValueType(User.class.getName())
.setStatisticsEnabled(true)
.setManagementEnabled(true)
.setExpiryPolicyFactory(
TimedExpiryPolicyFactory.of(Duration.ofMinutes(10)))
.setEvictionConfig(new EvictionConfig()
.setEvictionPolicy(EvictionPolicy.LRU)
.setSize(1000));
config.addCacheConfig(userCacheConfig);
// 创建 Hazelcast 实例
HazelcastInstance hazelcast = Hazelcast.newHazelcastInstance(config);
// 包装为 Spring CacheManager
return new HazelcastCacheManager(hazelcast);
}
/**
* 方式4:多重缓存管理器(主备或分层)
*/
@Bean
public CompositeCacheManager compositeCacheManager(
CacheManager ehcacheCacheManager,
CacheManager hazelcastCacheManager) {
List<CacheManager> managers = new ArrayList<>();
managers.add(ehcacheCacheManager); // 一级缓存:本地
managers.add(hazelcastCacheManager); // 二级缓存:分布式
CompositeCacheManager composite = new CompositeCacheManager();
composite.setCacheManagers(managers);
composite.setFallbackToNoOpCache(false); // 禁用无操作缓存回退
return composite;
}
}
三、注解详细用法与实现机制
3.1 @Cacheable 深度解析
@Service
@Slf4j
public class UserService {
/**
* 基础用法:简单缓存
*/
@Cacheable(value = "userCache", key = "#id")
public User getUserById(Long id) {
log.info("查询数据库获取用户: {}", id);
return userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
/**
* 使用 SpEL 表达式定义复杂键
*/
@Cacheable(
value = "userCache",
key = "T(org.springframework.util.StringUtils).hasText(#name) ? #name : #defaultName",
unless = "#result == null" // 结果为空时不缓存
)
public User getUserByName(String name, String defaultName) {
return userRepository.findByName(name)
.orElseGet(() -> userRepository.findByName(defaultName).orElse(null));
}
/**
* 条件缓存:基于方法参数的条件判断
*/
@Cacheable(
value = "userCache",
key = "#id",
condition = "#id > 1000", // 仅当ID大于1000时缓存
unless = "#result == null || #result.status == 'INACTIVE'" // 结果为空或状态为INACTIVE时不缓存
)
public User getUserByIdConditional(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 缓存同步:防止缓存击穿
*/
@Cacheable(
value = "userCache",
key = "#id",
sync = true // 添加同步锁,防止缓存击穿
)
public User getUserWithSync(Long id) {
log.info("执行数据库查询,防止缓存击穿: {}", id);
return userRepository.findById(id).orElse(null);
}
/**
* 多缓存名称:同时写入多个缓存
*/
@Cacheable(value = {"userCache", "userCacheV2"}, key = "#id")
public User getUserMultipleCaches(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 自定义缓存解析器
*/
@Cacheable(
value = "userCache",
keyGenerator = "customKeyGenerator", // 使用自定义键生成器
cacheManager = "customCacheManager", // 指定特定的缓存管理器
cacheResolver = "customCacheResolver" // 自定义缓存解析器
)
public User getUserWithCustomComponents(Long id) {
return userRepository.findById(id).orElse(null);
}
/**
* 统计信息集成:记录缓存命中率
*/
@Cacheable(
value = "userCache",
key = "#id",
cacheManager = "statisticsEnabledCacheManager"
)
public User getUserWithStatistics(Long id) {
// 获取缓存统计信息
Cache cache = cacheManager.getCache("userCache");
if (cache instanceof JCacheCache) {
javax.cache.Cache<Object, Object> nativeCache =
((JCacheCache) cache).getNativeCache();
CacheStatistics stats = nativeCache.getStatistics();
log.info("缓存命中率: {}%", stats.getCacheHitPercentage());
}
return userRepository.findById(id).orElse(null);
}
}
/**
* 自定义键生成器
*/
@Component("customKeyGenerator")
public class CustomKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object target, Method method, Object... params) {
// 生成自定义缓存键
return method.getName() + ":" +
Arrays.stream(params)
.map(Object::toString)
.collect(Collectors.joining(":"));
}
}
/**
* 自定义缓存解析器
*/
@Component("customCacheResolver")
public class CustomCacheResolver implements CacheResolver {
private final CacheManager cacheManager;
public CustomCacheResolver(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public Collection<? extends Cache> resolveCaches(
CacheOperationInvocationContext<?> context) {
// 根据上下文动态选择缓存
String cacheName = context.getOperation().getCacheNames().iterator().next();
// 可以根据业务规则动态选择缓存
if (isDistributedCacheRequired(context)) {
cacheName = cacheName + "-distributed";
}
Cache cache = cacheManager.getCache(cacheName);
return cache != null ? Collections.singletonList(cache) : Collections.emptyList();
}
private boolean isDistributedCacheRequired(
CacheOperationInvocationContext<?> context) {
// 实现业务逻辑判断
return true;
}
}
3.2 @CachePut 深度解析
@Service
@Slf4j
public class ProductService {
/**
* 基础用法:更新缓存
* 注意:@CachePut 总是执行方法体,然后更新缓存
*/
@CachePut(value = "productCache", key = "#product.id")
public Product updateProduct(Product product) {
log.info("更新产品: {}", product.getId());
Product saved = productRepository.save(product);
// 更新相关缓存
evictRelatedCaches(saved);
return saved;
}
/**
* 条件更新:只有满足条件时才更新缓存
*/
@CachePut(
value = "productCache",
key = "#product.id",
condition = "#product.price > 100.0", // 仅当价格大于100时更新缓存
unless = "#result == null" // 结果为空时不更新
)
public Product updateProductConditional(Product product) {
return productRepository.save(product);
}
/**
* 批量更新缓存
*/
@CachePut(value = "productCache", key = "#result.id")
public List<Product> batchUpdateProducts(List<Product> products) {
List<Product> savedProducts = productRepository.saveAll(products);
// 异步更新缓存统计
updateCacheStatisticsAsync("productCache");
return savedProducts;
}
/**
* 与 @Cacheable 配合使用
* 先使用 @Cacheable 读取,然后使用 @CachePut 更新
*/
@Cacheable(value = "productCache", key = "#id")
public Product getProduct(Long id) {
return productRepository.findById(id).orElse(null);
}
@CachePut(value = "productCache", key = "#product.id")
public Product updateAndCache(Product product) {
Product saved = productRepository.save(product);
// 手动刷新相关缓存
refreshRelatedCaches(saved);
return saved;
}
/**
* 异步缓存更新
*/
@Async
@CachePut(value = "productCache", key = "#product.id")
public CompletableFuture<Product> updateProductAsync(Product product) {
return CompletableFuture.supplyAsync(() -> {
Product saved = productRepository.save(product);
// 异步更新二级缓存
updateSecondaryCacheAsync(saved);
return saved;
});
}
private void evictRelatedCaches(Product product) {
// 逐出相关缓存条目
Cache categoryCache = cacheManager.getCache("categoryCache");
if (categoryCache != null) {
categoryCache.evict(product.getCategoryId());
}
}
private void updateCacheStatisticsAsync(String cacheName) {
CompletableFuture.runAsync(() -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache instanceof JCacheCache) {
javax.cache.Cache<Object, Object> nativeCache =
((JCacheCache) cache).getNativeCache();
CacheStatistics stats = nativeCache.getStatistics();
log.info("缓存 {} 统计: 命中率={}%",
cacheName, stats.getCacheHitPercentage());
}
});
}
}
3.3 @CacheEvict 深度解析
@Service
@Slf4j
public class OrderService {
/**
* 基础用法:逐出单个缓存条目
*/
@CacheEvict(value = "orderCache", key = "#orderId")
public void deleteOrder(Long orderId) {
log.info("删除订单: {}", orderId);
orderRepository.deleteById(orderId);
// 更新统计信息
updateDeletionMetrics(orderId);
}
/**
* 条件逐出:基于参数的条件判断
*/
@CacheEvict(
value = "orderCache",
key = "#orderId",
condition = "#orderId > 1000", // 仅当订单ID大于1000时逐出缓存
beforeInvocation = false // 默认为false,方法执行后逐出
)
public void deleteOrderConditional(Long orderId) {
orderRepository.deleteById(orderId);
}
/**
* 在方法执行前逐出缓存
* 适用于:先清除旧缓存,再执行更新操作
*/
@CacheEvict(
value = "orderCache",
key = "#order.id",
beforeInvocation = true // 方法执行前逐出缓存
)
@CachePut(
value = "orderCache",
key = "#result.id",
condition = "#result != null"
)
public Order updateOrder(Order order) {
log.info("更新订单: {}", order.getId());
return orderRepository.save(order);
}
/**
* 清空整个缓存
*/
@CacheEvict(value = "orderCache", allEntries = true)
public void clearOrderCache() {
log.info("清空订单缓存");
// 记录清空操作
logCacheClearEvent("orderCache");
}
/**
* 批量逐出缓存
*/
@CacheEvict(value = "orderCache", key = "#orderIds")
public void deleteOrders(List<Long> orderIds) {
log.info("批量删除订单: {}", orderIds);
orderRepository.deleteAllById(orderIds);
// 异步清理相关缓存
cleanRelatedCachesAsync(orderIds);
}
/**
* 连锁逐出:逐出多个相关缓存
*/
@CacheEvict(value = {"orderCache", "userOrderCache", "recentOrdersCache"},
key = "#orderId")
public void deleteOrderWithCascade(Long orderId) {
orderRepository.deleteById(orderId);
// 通知其他服务逐出缓存
notifyOtherServices(orderId);
}
/**
* 使用自定义逐出策略
*/
@CacheEvict(
value = "orderCache",
key = "#orderId",
cacheManager = "ehcacheCacheManager",
cacheResolver = "customCacheEvictResolver"
)
public void deleteOrderWithCustomEviction(Long orderId) {
orderRepository.deleteById(orderId);
}
/**
* 配合事务的缓存逐出
*/
@Transactional
@CacheEvict(value = "orderCache", key = "#orderId")
public void deleteOrderWithTransaction(Long orderId) {
// 1. 删除订单
orderRepository.deleteById(orderId);
// 2. 删除相关数据
orderItemRepository.deleteByOrderId(orderId);
paymentRepository.deleteByOrderId(orderId);
// 3. 发送事件
applicationEventPublisher.publishEvent(new OrderDeletedEvent(orderId));
}
private void updateDeletionMetrics(Long orderId) {
// 更新删除指标
meterRegistry.counter("order.deletion.count").increment();
log.info("订单 {} 删除完成,更新指标", orderId);
}
private void logCacheClearEvent(String cacheName) {
// 记录缓存清空事件
ApplicationEvent event = new CacheClearedEvent(
cacheName, System.currentTimeMillis());
applicationEventPublisher.publishEvent(event);
}
private void cleanRelatedCachesAsync(List<Long> orderIds) {
CompletableFuture.runAsync(() -> {
Cache userCache = cacheManager.getCache("userCache");
if (userCache != null) {
orderIds.forEach(orderId -> {
// 清理用户相关的订单缓存
userCache.evict("orders:" + orderId);
});
}
});
}
}
/**
* 自定义缓存逐出解析器
*/
@Component("customCacheEvictResolver")
public class CustomCacheEvictResolver implements CacheResolver {
private final CacheManager primaryCacheManager;
private final CacheManager backupCacheManager;
public CustomCacheEvictResolver(
@Qualifier("ehcacheCacheManager") CacheManager primary,
@Qualifier("hazelcastCacheManager") CacheManager backup) {
this.primaryCacheManager = primary;
this.backupCacheManager = backup;
}
@Override
public Collection<? extends Cache> resolveCaches(
CacheOperationInvocationContext<?> context) {
CacheEvict cacheEvict = context.getOperation()
.getClass().getAnnotation(CacheEvict.class);
Set<Cache> caches = new HashSet<>();
// 从主缓存管理器获取缓存
Arrays.stream(cacheEvict.value())
.map(primaryCacheManager::getCache)
.filter(Objects::nonNull)
.forEach(caches::add);
// 从备份缓存管理器获取缓存
if (cacheEvict.allEntries()) {
Arrays.stream(cacheEvict.value())
.map(backupCacheManager::getCache)
.filter(Objects::nonNull)
.forEach(caches::add);
}
return caches;
}
}
3.4 @Caching 组合注解
@Service
@Slf4j
public class ComplexCacheService {
/**
* 使用 @Caching 组合多个缓存操作
*/
@Caching(
cacheable = {
@Cacheable(value = "userCache", key = "#id"),
@Cacheable(value = "userDetailCache", key = "#id")
},
put = {
@CachePut(value = "userStatsCache", key = "#id"),
@CachePut(value = "recentUsersCache", key = "#id")
},
evict = {
@CacheEvict(value = "oldUserCache", key = "#id")
}
)
public User getUserWithMultipleCaches(Long id) {
log.info("获取用户信息,同时操作多个缓存");
User user = userRepository.findById(id).orElse(null);
if (user != null) {
// 异步更新用户访问统计
updateUserAccessStatsAsync(id);
}
return user;
}
/**
* 条件组合缓存
*/
@Caching(
cacheable = @Cacheable(
value = "productCache",
key = "#id",
condition = "#id > 0"
),
put = {
@CachePut(
value = "productViewCache",
key = "#id",
unless = "#result == null"
),
@CachePut(
value = "popularProductsCache",
key = "#id",
condition = "#result != null && #result.viewCount > 1000"
)
}
)
public Product getProductWithConditionalCaches(Long id) {
Product product = productRepository.findById(id).orElse(null);
if (product != null) {
// 增加浏览量
product.incrementViewCount();
productRepository.save(product);
}
return product;
}
/**
* 更新操作的多缓存管理
*/
@Caching(
put = {
@CachePut(value = "userCache", key = "#user.id"),
@CachePut(value = "userByEmailCache", key = "#user.email"),
@CachePut(value = "userByPhoneCache", key = "#user.phone")
},
evict = {
@CacheEvict(value = "inactiveUsersCache", allEntries = true),
@CacheEvict(value = "userListCache", allEntries = true)
}
)
public User updateUserWithComplexCaching(User user) {
log.info("更新用户信息,同步更新多个缓存");
User saved = userRepository.save(user);
// 发布用户更新事件
publishUserUpdatedEvent(saved);
return saved;
}
/**
* 删除操作的多缓存清理
*/
@Transactional
@Caching(
evict = {
@CacheEvict(value = "userCache", key = "#id"),
@CacheEvict(value = "userByEmailCache",
key = "#target.getUserEmail(#id)"),
@CacheEvict(value = "userByPhoneCache",
key = "#target.getUserPhone(#id)"),
@CacheEvict(value = "userPermissionsCache", key = "#id"),
@CacheEvict(value = "userRolesCache", key = "#id")
}
)
public void deleteUserWithCompleteCacheCleanup(Long id) {
log.info("删除用户: {}", id);
// 1. 删除用户
userRepository.deleteById(id);
// 2. 删除关联数据
userRoleRepository.deleteByUserId(id);
userPermissionRepository.deleteByUserId(id);
// 3. 记录删除日志
logUserDeletion(id);
}
/**
* 用于 SpEL 表达式的方法
*/
public String getUserEmail(Long userId) {
return userRepository.findById(userId)
.map(User::getEmail)
.orElse(null);
}
public String getUserPhone(Long userId) {
return userRepository.findById(userId)
.map(User::getPhone)
.orElse(null);
}
private void updateUserAccessStatsAsync(Long userId) {
CompletableFuture.runAsync(() -> {
try {
userAccessStatsService.recordAccess(userId);
} catch (Exception e) {
log.error("更新用户访问统计失败: {}", userId, e);
}
});
}
private void publishUserUpdatedEvent(User user) {
UserUpdatedEvent event = new UserUpdatedEvent(
user.getId(),
user.getEmail(),
System.currentTimeMillis()
);
applicationEventPublisher.publishEvent(event);
}
private void logUserDeletion(Long userId) {
auditLogService.log(
"USER_DELETION",
String.format("用户 %d 已被删除", userId),
userId
);
}
}
四、与特定 JCache 提供程序集成
4.1 Ehcache 3 深度集成
@Configuration
@EnableCaching
public class Ehcache3Configuration {
/**
* Ehcache 3 高级配置
*/
@Bean
public CacheManager ehcacheCacheManager() {
// 1. 创建 Ehcache 缓存管理器
CacheManager cacheManager = CacheManagerBuilder.newCacheManagerBuilder()
.withCache("userCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, User.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(1000, EntryUnit.ENTRIES) // 堆内存:1000个条目
.offheap(100, MemoryUnit.MB) // 堆外内存:100MB
.disk(1, MemoryUnit.GB, true) // 磁盘:1GB,持久化
.build())
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(
Duration.ofMinutes(30))) // 30分钟不访问过期
.withSizeOfMaxObjectGraph(1000) // 最大对象图大小
.withSizeOfMaxObjectSize(1, MemoryUnit.MB) // 最大对象大小1MB
.withService(
new DefaultStatisticsProviderConfiguration(
true, 1000, true, true, true)) // 统计配置
.add(new DefaultPersistenceConfiguration(
new File(getStoragePath(), "ehcache"))) // 持久化配置
.build())
.withCache("productCache",
CacheConfigurationBuilder.newCacheConfigurationBuilder(
String.class, Product.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(5000, EntryUnit.ENTRIES)
.build())
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofHours(1))) // 1小时后过期
.withLoaderWriter(new CacheLoaderWriter<String, Product>() {
@Override
public Product load(String key) throws Exception {
// 缓存未命中时的加载逻辑
return productRepository.findBySku(key);
}
@Override
public void write(String key, Product value) throws Exception {
// 写入缓存时的回调
log.info("缓存写入: {} = {}", key, value);
}
@Override
public void delete(String key) throws Exception {
// 删除缓存时的回调
log.info("缓存删除: {}", key);
}
})
.build())
.build(true); // 自动初始化
// 2. 注册为 Spring CacheManager
return new EhCacheCacheManager(cacheManager);
}
/**
* 集成 Spring Boot 注解的 Ehcache 管理器
*/
@Bean
public JCacheManagerCustomizer ehcacheManagerCustomizer() {
return cacheManager -> {
// 配置默认模板
MutableConfiguration<Object, Object> config =
new MutableConfiguration<>()
.setTypes(Object.class, Object.class)
.setStoreByValue(false)
.setExpiryPolicyFactory(
CreatedExpiryPolicy.factoryOf(Duration.ONE_HOUR))
.setStatisticsEnabled(true);
cacheManager.createCache("default", config);
};
}
/**
* Ehcache 统计信息监控
*/
@Component
public class EhcacheStatisticsMonitor {
private final CacheManager cacheManager;
private final ScheduledExecutorService scheduler;
public EhcacheStatisticsMonitor(CacheManager cacheManager) {
this.cacheManager = cacheManager;
this.scheduler = Executors.newScheduledThreadPool(1);
startMonitoring();
}
private void startMonitoring() {
scheduler.scheduleAtFixedRate(() -> {
if (cacheManager instanceof EhCacheCacheManager) {
org.ehcache.CacheManager ehcacheManager =
((EhCacheCacheManager) cacheManager).getCacheManager();
ehcacheManager.getRuntimeConfiguration()
.getCacheConfigurations()
.forEach((cacheName, config) -> {
org.ehcache.Cache<?, ?> cache =
ehcacheManager.getCache(cacheName,
config.getKeyType(), config.getValueType());
// 获取统计信息
org.ehcache.statistics.CacheStatistics stats =
cache.getStatistics();
log.info("缓存 {} 统计: 命中率={}%, 平均获取时间={}ns",
cacheName,
stats.getCacheHitPercentage(),
stats.getAverageGetTime());
});
}
}, 0, 5, TimeUnit.MINUTES);
}
}
private String getStoragePath() {
return System.getProperty("java.io.tmpdir") + "/cache-data";
}
}
4.2 Hazelcast 深度集成
@Configuration
@EnableCaching
public class HazelcastConfiguration {
/**
* Hazelcast 高级配置
*/
@Bean
public Config hazelcastConfig() {
Config config = new Config();
// 网络配置
config.getNetworkConfig()
.setPort(5701)
.setPortAutoIncrement(true)
.setReuseAddress(true);
// 管理配置
config.getManagementCenterConfig()
.setEnabled(true)
.setUrl("http://localhost:8080/mancenter");
// 序列化配置
config.getSerializationConfig()
.addPortableFactory(1, new PortableFactoryImpl());
// 缓存配置
CacheSimpleConfig userCacheConfig = new CacheSimpleConfig()
.setName("userCache")
.setKeyType(String.class.getName())
.setValueType(User.class.getName())
.setStatisticsEnabled(true)
.setManagementEnabled(true)
.setReadThrough(true) // 启用读取穿透
.setWriteThrough(true) // 启用写入穿透
.setCacheLoaderFactory(
"com.example.UserCacheLoaderFactory")
.setCacheWriterFactory(
"com.example.UserCacheWriterFactory")
.setExpiryPolicyFactory(
TimedExpiryPolicyFactory.of(
Duration.ofMinutes(30),
ExpiryPolicyType.ACCESSED))
.setEvictionConfig(new EvictionConfig()
.setEvictionPolicy(EvictionPolicy.LRU)
.setSize(10000)
.setMaxSizePolicy(MaxSizePolicy.PER_NODE))
.setInMemoryFormat(InMemoryFormat.OBJECT)
.setBackupCount(1)
.setAsyncBackupCount(0);
config.addCacheConfig(userCacheConfig);
return config;
}
/**
* Hazelcast 缓存管理器
*/
@Bean
public CacheManager hazelcastCacheManager(HazelcastInstance hazelcastInstance) {
HazelcastCacheManager cacheManager = new HazelcastCacheManager(hazelcastInstance);
// 设置缓存配置
cacheManager.setTransactionAware(true);
cacheManager.setFallbackToNoOpCache(false);
return cacheManager;
}
/**
* 分布式缓存监听器
*/
@Component
public class HazelcastCacheListener {
@EventListener
public void handleCacheEvent(CacheEvent event) {
// 处理缓存事件
switch (event.getEventType()) {
case CREATED:
log.info("缓存创建: {}", event.getKey());
break;
case UPDATED:
log.info("缓存更新: {}", event.getKey());
break;
case REMOVED:
log.info("缓存移除: {}", event.getKey());
break;
case EXPIRED:
log.info("缓存过期: {}", event.getKey());
break;
}
}
}
/**
* Hazelcast 缓存加载器
*/
public class UserCacheLoader implements CacheLoader<Long, User> {
private final UserRepository userRepository;
public UserCacheLoader(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User load(Long key) {
log.info("缓存未命中,从数据库加载用户: {}", key);
return userRepository.findById(key).orElse(null);
}
@Override
public Map<Long, User> loadAll(Set<Long> keys) {
log.info("批量加载用户: {}", keys);
return userRepository.findAllById(keys).stream()
.collect(Collectors.toMap(User::getId, Function.identity()));
}
@Override
public Iterable<Long> loadAllKeys() {
return userRepository.findAllIds();
}
}
/**
* Hazelcast 缓存写入器
*/
public class UserCacheWriter implements CacheWriter<Long, User> {
private final UserRepository userRepository;
public UserCacheWriter(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void write(CacheEntry<? extends Long, ? extends User> entry) {
log.info("写入缓存到数据库: {}", entry.getKey());
userRepository.save(entry.getValue());
}
@Override
public void writeAll(Collection<CacheEntry<? extends Long, ? extends User>> entries) {
log.info("批量写入缓存到数据库: {} 个条目", entries.size());
entries.forEach(entry -> userRepository.save(entry.getValue()));
}
@Override
public void delete(Object key) {
log.info("从数据库删除: {}", key);
userRepository.deleteById((Long) key);
}
@Override
public void deleteAll(Collection<?> keys) {
log.info("批量从数据库删除: {} 个键", keys.size());
keys.forEach(key -> userRepository.deleteById((Long) key));
}
}
}
4.3 多缓存提供程序协同工作
@Configuration
@EnableCaching
@Slf4j
public class MultiCacheProviderConfiguration {
/**
* 分层缓存配置:L1 (Caffeine) + L2 (Ehcache) + L3 (Hazelcast)
*/
@Bean
@Primary
public CacheManager layeredCacheManager() {
// 第一层:Caffeine(内存缓存,最快)
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCaffeine(Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats());
// 第二层:Ehcache(本地磁盘缓存)
CacheManager ehcacheCacheManager = ehcacheCacheManager();
// 第三层:Hazelcast(分布式缓存)
CacheManager hazelcastCacheManager = hazelcastCacheManager();
// 创建分层缓存管理器
LayeredCacheManager layeredCacheManager = new LayeredCacheManager(
caffeineCacheManager,
ehcacheCacheManager,
hazelcastCacheManager
);
return layeredCacheManager;
}
/**
* 智能缓存路由器:根据数据特征选择缓存提供程序
*/
@Bean
public CacheManager smartCacheRouter() {
Map<String, CacheManager> cacheManagers = new HashMap<>();
cacheManagers.put("ehcache", ehcacheCacheManager());
cacheManagers.put("hazelcast", hazelcastCacheManager());
cacheManagers.put("redis", redisCacheManager());
return new SmartCacheRouter(cacheManagers);
}
/**
* 自定义分层缓存管理器
*/
public static class LayeredCacheManager implements CacheManager {
private final List<CacheManager> layers;
public LayeredCacheManager(CacheManager... layers) {
this.layers = Arrays.asList(layers);
}
@Override
public Cache getCache(String name) {
List<Cache> caches = layers.stream()
.map(layer -> layer.getCache(name))
.filter(Objects::nonNull)
.collect(Collectors.toList());
return new LayeredCache(name, caches);
}
@Override
public Collection<String> getCacheNames() {
return layers.stream()
.map(CacheManager::getCacheNames)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
}
}
/**
* 分层缓存实现
*/
public static class LayeredCache implements Cache {
private final String name;
private final List<Cache> layers;
public LayeredCache(String name, List<Cache> layers) {
this.name = name;
this.layers = layers;
}
@Override
public String getName() {
return name;
}
@Override
public Object getNativeCache() {
return layers;
}
@Override
public ValueWrapper get(Object key) {
// 从第一层开始查找
for (Cache layer : layers) {
ValueWrapper value = layer.get(key);
if (value != null) {
// 找到值,填充上层缓存(回填)
fillUpperLayers(key, value.get());
return value;
}
}
return null;
}
@Override
public <T> T get(Object key, Class<T> type) {
// 从第一层开始查找
for (Cache layer : layers) {
T value = layer.get(key, type);
if (value != null) {
// 找到值,填充上层缓存
fillUpperLayers(key, value);
return value;
}
}
return null;
}
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
// 尝试从缓存获取
T value = get(key, (Class<T>) Object.class);
if (value != null) {
return value;
}
// 所有层都未命中,执行加载
try {
value = valueLoader.call();
if (value != null) {
// 写入所有层
put(key, value);
}
return value;
} catch (Exception e) {
throw new ValueRetrievalException(key, valueLoader, e);
}
}
@Override
public void put(Object key, Object value) {
// 写入所有层
layers.forEach(layer -> layer.put(key, value));
}
@Override
public void evict(Object key) {
// 从所有层逐出
layers.forEach(layer -> layer.evict(key));
}
@Override
public void clear() {
// 清空所有层
layers.forEach(Cache::clear);
}
private void fillUpperLayers(Object key, Object value) {
// 将找到的值填充到上层缓存
for (int i = 0; i < layers.indexOf(layers.get(0)); i++) {
layers.get(i).put(key, value);
}
}
}
}
五、性能监控与调优
5.1 缓存性能监控
@Component
@Slf4j
public class CachePerformanceMonitor {
private final CacheManager cacheManager;
private final MeterRegistry meterRegistry;
private final ScheduledExecutorService scheduler;
public CachePerformanceMonitor(CacheManager cacheManager,
MeterRegistry meterRegistry) {
this.cacheManager = cacheManager;
this.meterRegistry = meterRegistry;
this.scheduler = Executors.newScheduledThreadPool(1);
startMonitoring();
}
private void startMonitoring() {
// 每30秒收集一次指标
scheduler.scheduleAtFixedRate(this::collectMetrics,
0, 30, TimeUnit.SECONDS);
}
private void collectMetrics() {
cacheManager.getCacheNames().forEach(cacheName -> {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) return;
// 监控命中率
monitorHitRate(cacheName, cache);
// 监控响应时间
monitorResponseTime(cacheName, cache);
// 监控内存使用
monitorMemoryUsage(cacheName, cache);
});
}
private void monitorHitRate(String cacheName, Cache cache) {
if (cache instanceof JCacheCache) {
javax.cache.Cache<Object, Object> nativeCache =
((JCacheCache) cache).getNativeCache();
CacheStatistics stats = nativeCache.getStatistics();
// 记录到 Micrometer
Gauge.builder("cache.hit.rate",
() -> stats.getCacheHitPercentage())
.tag("cache", cacheName)
.description("缓存命中率")
.register(meterRegistry);
// 记录命中/未命中计数
Counter.builder("cache.operations")
.tag("cache", cacheName)
.tag("type", "hits")
.register(meterRegistry)
.increment(stats.getCacheHits());
Counter.builder("cache.operations")
.tag("cache", cacheName)
.tag("type", "misses")
.register(meterRegistry)
.increment(stats.getCacheMisses());
}
}
private void monitorResponseTime(String cacheName, Cache cache) {
if (cache instanceof JCacheCache) {
javax.cache.Cache<Object, Object> nativeCache =
((JCacheCache) cache).getNativeCache();
CacheStatistics stats = nativeCache.getStatistics();
// 记录平均获取时间
Gauge.builder("cache.get.time",
() -> stats.getAverageGetTime() / 1_000_000.0) // 转换为ms
.tag("cache", cacheName)
.description("平均获取时间(ms)")
.register(meterRegistry);
// 记录平均写入时间
Gauge.builder("cache.put.time",
() -> stats.getAveragePutTime() / 1_000_000.0)
.tag("cache", cacheName)
.description("平均写入时间(ms)")
.register(meterRegistry);
}
}
private void monitorMemoryUsage(String cacheName, Cache cache) {
// 根据缓存实现类型监控内存使用
if (cache.getNativeCache() instanceof com.github.benmanes.caffeine.cache.Cache) {
com.github.benmanes.caffeine.cache.Cache<?, ?> caffeineCache =
(com.github.benmanes.caffeine.cache.Cache<?, ?>) cache.getNativeCache();
com.github.benmanes.caffeine.cache.stats.CacheStats stats =
caffeineCache.stats();
Gauge.builder("cache.size", caffeineCache::estimatedSize)
.tag("cache", cacheName)
.description("缓存条目数量")
.register(meterRegistry);
}
}
/**
* 缓存健康检查
*/
@Component
public class CacheHealthIndicator implements HealthIndicator {
private final CacheManager cacheManager;
public CacheHealthIndicator(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
@Override
public Health health() {
Map<String, Object> details = new HashMap<>();
boolean allHealthy = true;
for (String cacheName : cacheManager.getCacheNames()) {
Cache cache = cacheManager.getCache(cacheName);
if (cache == null) {
details.put(cacheName, "NOT_FOUND");
allHealthy = false;
continue;
}
// 检查缓存是否可访问
try {
// 简单的健康检查:尝试获取缓存统计
if (cache instanceof JCacheCache) {
javax.cache.Cache<Object, Object> nativeCache =
((JCacheCache) cache).getNativeCache();
CacheStatistics stats = nativeCache.getStatistics();
details.put(cacheName + ".hitRate",
String.format("%.2f%%", stats.getCacheHitPercentage()));
}
details.put(cacheName, "HEALTHY");
} catch (Exception e) {
details.put(cacheName, "UNHEALTHY: " + e.getMessage());
allHealthy = false;
}
}
Health.Builder builder = allHealthy ?
Health.up() : Health.down();
return builder.withDetails(details).build();
}
}
}
5.2 缓存调优配置
@Configuration
@EnableCaching
@Slf4j
public class CacheTuningConfiguration {
/**
* 动态缓存配置
*/
@Bean
public CacheManager dynamicCacheManager() {
return new DynamicCacheManager() {
@Override
protected Cache createCache(String name) {
// 根据缓存名称动态创建不同的配置
CacheConfiguration<?, ?> config = createCacheConfig(name);
return new DynamicCache(name, config);
}
};
}
private CacheConfiguration<?, ?> createCacheConfig(String cacheName) {
// 根据业务特征配置缓存
if (cacheName.startsWith("user")) {
return CacheConfigurationBuilder.newCacheConfigurationBuilder(
String.class, User.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(10000, EntryUnit.ENTRIES)
.offheap(500, MemoryUnit.MB)
.build())
.withExpiry(ExpiryPolicyBuilder.timeToIdleExpiration(
Duration.ofMinutes(30)))
.withSizeOfMaxObjectGraph(5000)
.build();
} else if (cacheName.startsWith("product")) {
return CacheConfigurationBuilder.newCacheConfigurationBuilder(
Long.class, Product.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(50000, EntryUnit.ENTRIES)
.build())
.withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(
Duration.ofHours(1)))
.build();
} else {
// 默认配置
return CacheConfigurationBuilder.newCacheConfigurationBuilder(
Object.class, Object.class,
ResourcePoolsBuilder.newResourcePoolsBuilder()
.heap(1000, EntryUnit.ENTRIES)
.build())
.withExpiry(ExpiryPolicyBuilder.noExpiration())
.build();
}
}
/**
* 缓存预热策略
*/
@Component
public class CacheWarmUpStrategy implements ApplicationListener<ContextRefreshedEvent> {
private final UserRepository userRepository;
private final CacheManager cacheManager;
public CacheWarmUpStrategy(UserRepository userRepository,
CacheManager cacheManager) {
this.userRepository = userRepository;
this.cacheManager = cacheManager;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
log.info("开始缓存预热…");
// 预热用户缓存(前1000个活跃用户)
warmUpUserCache();
// 预热产品缓存
warmUpProductCache();
log.info("缓存预热完成");
}
private void warmUpUserCache() {
Cache userCache = cacheManager.getCache("userCache");
if (userCache == null) return;
List<User> activeUsers = userRepository.findTop1000ByStatus("ACTIVE");
activeUsers.parallelStream().forEach(user -> {
userCache.put(user.getId(), user);
});
log.info("预热用户缓存: {} 个条目", activeUsers.size());
}
private void warmUpProductCache() {
Cache productCache = cacheManager.getCache("productCache");
if (productCache == null) return;
// 预热热门产品
List<Product> popularProducts = productRepository.findTop500ByViewCountDesc();
popularProducts.forEach(product -> {
productCache.put(product.getId(), product);
});
log.info("预热产品缓存: {} 个条目", popularProducts.size());
}
}
/**
* 缓存刷新策略
*/
@Component
public class CacheRefreshScheduler {
private final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(2);
@PostConstruct
public void init() {
// 每5分钟刷新用户缓存
scheduler.scheduleAtFixedRate(this::refreshUserCache,
0, 5, TimeUnit.MINUTES);
// 每10分钟刷新产品缓存
scheduler.scheduleAtFixedRate(this::refreshProductCache,
0, 10, TimeUnit.MINUTES);
}
private void refreshUserCache() {
log.info("刷新用户缓存…");
// 实现刷新逻辑
}
private void refreshProductCache() {
log.info("刷新产品缓存…");
// 实现刷新逻辑
}
}
}
六、面试深度解析
6.1 常见面试问题
Q1:Spring Boot 中 @Cacheable 和 JCache 的 @CacheResult 有什么区别?
参考答案:
相同点:
1. 都是方法级缓存注解
2. 都支持键表达式和条件缓存
3. 都可以集成各种缓存提供程序
不同点:
架构层面:
1. 注解来源不同:
– @Cacheable:Spring 缓存抽象(org.springframework.cache.annotation)
– @CacheResult:JSR-107 标准(javax.cache.annotation)
2. 集成方式不同:
– @Cacheable:通过 Spring AOP 实现
– @CacheResult:需要 JCache 拦截器(CDI 或 Spring 代理)
3. 功能特性不同:
– @Cacheable:支持 sync 属性防止缓存击穿
– @CacheResult:支持异常缓存(@CacheResult(exceptionCacheName))
4. 配置方式不同:
– @Cacheable:通过 Spring CacheManager 配置
– @CacheResult:通过 JCache CacheResolver 配置
集成建议:
1. 纯 Spring 项目:使用 @Cacheable
2. 需要 JSR-107 标准:使用 @CacheResult
3. 混合使用:可通过 Spring 的 JCache 适配器支持
实际集成示例:
```java
// Spring 配置启用 JCache 注解支持
@Configuration
@EnableCaching
@EnableJCache // 启用 JCache 注解支持
public class CacheConfig {
}
// 可以混合使用
@Service
public class UserService {
@Cacheable("users") // Spring 注解
public User getBySpring(Long id) { … }
@CacheResult(cacheName = "users") // JCache 注解
public User getByJCache(Long id) { … }
}
**Q2:在分布式环境下,@CacheEvict 如何保证缓存一致性?**
**参考答案:**
分布式缓存一致性挑战:
解决方案:
方案1:事务性缓存(2PC模式)
@Transactional
@CacheEvict(value = "userCache", key = "#userId")
public void updateUser(Long userId, User user) {
// 1. 更新数据库
userRepository.save(user);
// 2. 缓存逐出在事务提交后执行
// Spring 会确保在事务成功提交后才逐出缓存
}
方案2:发布/订阅模式(事件驱动)
@Component
public class CacheEvictPublisher {
private final ApplicationEventPublisher eventPublisher;
@CacheEvict(value = "userCache", key = "#userId")
public void deleteUser(Long userId) {
// 1. 本地逐出缓存
userRepository.deleteById(userId);
// 2. 发布分布式事件
eventPublisher.publishEvent(new UserDeletedEvent(userId));
}
}
@Component
public class CacheEvictListener {
@EventListener
@Async
public void handleUserDeleted(UserDeletedEvent event) {
// 所有节点监听事件,逐出本地缓存
cacheManager.getCache("userCache").evict(event.getUserId());
}
}
方案3:使用分布式锁
@CacheEvict(value = "userCache", key = "#userId")
public void deleteUserWithLock(Long userId) {
// 获取分布式锁
Lock lock = distributedLockManager.getLock("user:" + userId);
try {
lock.lock();
userRepository.deleteById(userId);
} finally {
lock.unlock();
}
}
方案4:版本控制(乐观锁)
@Entity
public class User {
@Version
private Long version; // 版本号
}
@CachePut(value = "userCache", key = "#user.id")
public User updateUserWithVersion(User user) {
// 使用版本号防止并发冲突
return userRepository.save(user);
}
最佳实践:
**Q3:如何监控和调优 Spring Boot 中的缓存性能?**
**参考答案:**
监控指标体系:
监控实现:
@Bean
public MeterBinder cacheMetrics(CacheManager cacheManager) {
return new CacheMetrics(cacheManager,
Tags.of("application", "myapp"));
}
management:
endpoints:
web:
exposure:
include: health,metrics,cache
metrics:
export:
prometheus:
enabled: true
@Component
public class CacheHealthIndicator implements HealthIndicator {
@Override
public Health health() {
// 检查缓存健康状况
}
}
调优策略:
// 基于命中率动态调整容量
if (hitRate < 0.3) {
// 增加缓存容量
cacheManager.resizeCache("userCache", 20000);
}
// 基于访问模式调整TTL
@Cacheable(value = "userCache",
key = "#id",
unless = "#result != null && #result.lastAccess < T(java.time.Instant).now().minusSeconds(3600)")
public User getUser(Long id) { ... }
// 使用高效的序列化
config.setInMemoryFormat(InMemoryFormat.BINARY);
// 优化Redis连接池
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(100);
poolConfig.setMaxIdle(20);
- 命中率 < 50%:警告
- 平均响应时间 > 100ms:警告
- 内存使用 > 80%:告警
- 网络延迟 > 50ms:警告
调优工具:
## 七、最佳实践总结
### 7.1 配置最佳实践
```yaml
# application-prod.yml 生产环境配置
spring:
cache:
type: jcache
jcache:
provider: org.ehcache.jsr107.EhcacheCachingProvider
config: classpath:ehcache-prod.xml
# 缓存通用配置
cache-names: user,product,order,inventory
# Redis 缓存配置(如果使用)
redis:
time-to-live: 300000 # 5分钟
cache-null-values: false
key-prefix: "cache:"
use-key-prefix: true
enable-statistics: true
# Ehcache 生产配置
ehcache:
maxBytesLocalHeap: 512M
maxBytesLocalOffHeap: 2G
eternal: false
diskPersistent: true
diskExpiryThreadIntervalSeconds: 120
7.2 代码最佳实践
/**
* 缓存使用的最佳实践示例
*/
@Service
@Slf4j
public class BestPracticeService {
// 1. 使用常量定义缓存名称
public static final String USER_CACHE = "userCache";
public static final String PRODUCT_CACHE = "productCache";
// 2. 合理的键设计
@Cacheable(value = USER_CACHE, key = "'user:' + #id")
public User getUserById(Long id) { ... }
// 3. 条件缓存避免缓存无效数据
@Cacheable(value = USER_CACHE, key = "#id",
condition = "#id != null",
unless = "#result == null || #result.status == 'DELETED'")
public User getUserConditional(Long id) { ... }
// 4. 批量操作优化
@Cacheable(value = USER_CACHE, key = "#ids.hashCode()")
public List<User> getUsersBatch(List<Long> ids) { ... }
// 5. 异步缓存更新
@Async
@CachePut(value = USER_CACHE, key = "#user.id")
public CompletableFuture<User> updateUserAsync(User user) { ... }
// 6. 缓存预热
@PostConstruct
public void warmUpCache() {
// 预热常用数据
}
// 7. 监控集成
@Cacheable(value = USER_CACHE, key = "#id",
cacheManager = "monitoredCacheManager")
public User getUserWithMonitoring(Long id) { ... }
}
7.3 故障处理最佳实践
@Component
@Slf4j
public class CacheFailureHandler {
/**
* 缓存降级策略
*/
@Cacheable(value = "userCache", key = "#id",
unless = "#result == null")
@Fallback(fallbackMethod = "getUserFromDatabase")
public User getUserWithFallback(Long id) {
// 尝试从缓存获取
return cacheManager.getCache("userCache").get(id, User.class);
}
public User getUserFromDatabase(Long id) {
log.warn("缓存降级,从数据库获取用户: {}", id);
return userRepository.findById(id).orElse(null);
}
/**
* 缓存击穿防护
*/
@Cacheable(value = "hotProductCache", key = "#id", sync = true)
public Product getHotProduct(Long id) {
// sync=true 防止缓存击穿
return productRepository.findById(id).orElse(null);
}
/**
* 缓存雪崩防护
*/
@Cacheable(value = "configCache", key = "#key",
cacheManager = "randomTtlCacheManager")
public String getConfig(String key) {
// 使用随机TTL防止雪崩
return configRepository.findByKey(key);
}
/**
* 缓存穿透防护
*/
@Cacheable(value = "userCache", key = "#id",
condition = "#id != null && #id > 0",
unless = "#result == null")
public User getUserWithPenetrationProtection(Long id) {
// 前置条件过滤非法请求
User user = userRepository.findById(id).orElse(null);
// 即使为空也缓存短时间,防止穿透
if (user == null) {
cacheManager.getCache("nullCache").put(id, new NullObject());
}
return user;
}
}
通过以上详细的实现,Spring Boot 缓存注解可以与各种 JCache 提供程序(如 Ehcache 3、Hazelcast)深度集成,实现高性能、高可用的缓存系统。

