第12集Java实战深入探讨SpringBoot中的缓存框架集成
|字数总计:5.1k|阅读时长:25分钟|阅读量:
引言
在上一集中,我们深入了解了HTTP缓存机制。本集我们将继续探讨Spring Boot中的缓存框架集成,这是提升应用性能的另一个重要手段。Spring Boot提供了统一的缓存抽象,支持多种缓存实现,包括Redis、EhCache、Caffeine等。通过合理配置和使用缓存框架,可以显著提升应用的响应速度和并发处理能力。
Spring Boot缓存抽象
什么是Spring Cache
Spring Cache是Spring框架提供的缓存抽象,它提供了一种声明式的缓存管理方式。通过注解的方式,开发者可以轻松地在方法上添加缓存功能,而无需关心底层的缓存实现细节。
Spring Cache的核心特性
- 声明式缓存:通过注解方式管理缓存
- 多种实现支持:支持Redis、EhCache、Caffeine等多种缓存实现
- 统一抽象:提供统一的缓存操作接口
- 自动配置:Spring Boot提供自动配置支持
- 灵活配置:支持多种缓存策略和配置选项
启用Spring Cache
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @SpringBootApplication @EnableCaching public class CacheApplication { public static void main(String[] args) { SpringApplication.run(CacheApplication.class, args); } @Bean public CacheManager cacheManager() { SimpleCacheManager cacheManager = new SimpleCacheManager(); cacheManager.setCaches(Arrays.asList( new ConcurrentMapCache("users"), new ConcurrentMapCache("products"), new ConcurrentMapCache("orders") )); return cacheManager; } }
|
Spring Cache注解详解
1. @Cacheable注解
@Cacheable注解用于标注将方法的返回结果缓存,适用于查询操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| @Service public class UserService { @Autowired private UserRepository userRepository; @Cacheable(value = "users", key = "#id") public User getUserById(Long id) { System.out.println("从数据库查询用户: " + id); return userRepository.findById(id).orElse(null); } @Cacheable(value = "users", key = "#id", condition = "#id > 0") public User getUserByIdWithCondition(Long id) { System.out.println("条件缓存查询用户: " + id); return userRepository.findById(id).orElse(null); } @Cacheable(value = "users", key = "#id", unless = "#result == null") public User getUserByIdUnless(Long id) { System.out.println("排除缓存查询用户: " + id); return userRepository.findById(id).orElse(null); } @Cacheable(value = "users", key = "#name + '_' + #email") public User getUserByNameAndEmail(String name, String email) { System.out.println("复合键缓存查询用户: " + name + ", " + email); return userRepository.findByNameAndEmail(name, email); } @Cacheable(value = "users", keyGenerator = "customKeyGenerator") public User getUserByCustomKey(Long id) { System.out.println("自定义键生成器查询用户: " + id); return userRepository.findById(id).orElse(null); } }
|
2. @CachePut注解
@CachePut注解用于更新缓存,方法每次都会执行,并将结果更新到缓存中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Service public class UserService { @CachePut(value = "users", key = "#user.id") public User updateUser(User user) { System.out.println("更新用户: " + user.getId()); return userRepository.save(user); } @CachePut(value = "users", key = "#result.id") public User createUser(User user) { System.out.println("创建用户: " + user.getName()); return userRepository.save(user); } @CachePut(value = "users", key = "#user.id", condition = "#user.active == true") public User updateActiveUser(User user) { System.out.println("更新活跃用户: " + user.getId()); return userRepository.save(user); } }
|
3. @CacheEvict注解
@CacheEvict注解用于清除缓存,常用于删除或更新操作后清除缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| @Service public class UserService { @CacheEvict(value = "users", key = "#id") public void deleteUser(Long id) { System.out.println("删除用户: " + id); userRepository.deleteById(id); } @CacheEvict(value = "users", allEntries = true) public void clearAllUserCache() { System.out.println("清除所有用户缓存"); } @CacheEvict(value = "users", key = "#id", condition = "#id > 0") public void deleteUserWithCondition(Long id) { System.out.println("条件删除用户: " + id); userRepository.deleteById(id); } @CacheEvict(value = "users", key = "#id", beforeInvocation = true) public void deleteUserBeforeInvocation(Long id) { System.out.println("删除前清除缓存: " + id); userRepository.deleteById(id); } }
|
4. @Caching注解
@Caching注解用于组合多个缓存操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Service public class UserService { @Caching( cacheable = { @Cacheable(value = "users", key = "#id"), @Cacheable(value = "userProfiles", key = "#id") }, put = { @CachePut(value = "userStats", key = "#result.id") }, evict = { @CacheEvict(value = "userList", allEntries = true) } ) public User getUserWithMultipleCaches(Long id) { System.out.println("多缓存操作查询用户: " + id); return userRepository.findById(id).orElse(null); } }
|
5. @CacheConfig注解
@CacheConfig注解用于在类级别配置缓存:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Service @CacheConfig(cacheNames = "users", keyGenerator = "customKeyGenerator") public class UserService { @Cacheable public User getUserById(Long id) { System.out.println("使用类级别配置查询用户: " + id); return userRepository.findById(id).orElse(null); } @CachePut(key = "#user.id") public User updateUser(User user) { System.out.println("使用类级别配置更新用户: " + user.getId()); return userRepository.save(user); } @CacheEvict public void deleteUser(Long id) { System.out.println("使用类级别配置删除用户: " + id); userRepository.deleteById(id); } }
|
Redis缓存集成
1. Redis配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| @Configuration @EnableCaching public class RedisCacheConfig { @Value("${spring.redis.host:localhost}") private String redisHost; @Value("${spring.redis.port:6379}") private int redisPort; @Value("${spring.redis.password:}") private String redisPassword; @Value("${spring.redis.database:0}") private int redisDatabase; @Bean public LettuceConnectionFactory redisConnectionFactory() { RedisStandaloneConfiguration config = new RedisStandaloneConfiguration(); config.setHostName(redisHost); config.setPort(redisPort); config.setPassword(redisPassword); config.setDatabase(redisDatabase); return new LettuceConnectionFactory(config); } @Bean public RedisTemplate<String, Object> redisTemplate() { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory()); template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(new GenericJackson2JsonRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); template.afterPropertiesSet(); return template; } @Bean public CacheManager cacheManager() { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(10)) .serializeKeysWith(RedisSerializationContext.SerializationPair .fromSerializer(new StringRedisSerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair .fromSerializer(new GenericJackson2JsonRedisSerializer())); return RedisCacheManager.builder(redisConnectionFactory()) .cacheDefaults(config) .build(); } @Bean public KeyGenerator customKeyGenerator() { return (target, method, params) -> { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()); sb.append("."); sb.append(method.getName()); for (Object param : params) { sb.append("."); sb.append(param.toString()); } return sb.toString(); }; } }
|
2. Redis缓存服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| @Service public class RedisCacheService { @Autowired private RedisTemplate<String, Object> redisTemplate; public void setCache(String key, Object value, long timeout) { redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS); } public Object getCache(String key) { return redisTemplate.opsForValue().get(key); } public void deleteCache(String key) { redisTemplate.delete(key); } public void deleteCacheByPattern(String pattern) { Set<String> keys = redisTemplate.keys(pattern); if (keys != null && !keys.isEmpty()) { redisTemplate.delete(keys); } } public boolean hasCache(String key) { return redisTemplate.hasKey(key); } public void expireCache(String key, long timeout) { redisTemplate.expire(key, timeout, TimeUnit.SECONDS); } public long getCacheExpire(String key) { return redisTemplate.getExpire(key, TimeUnit.SECONDS); } }
|
3. Redis缓存应用示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| @RestController @RequestMapping("/api/users") public class UserController { @Autowired private UserService userService; @Autowired private RedisCacheService redisCacheService; @GetMapping("/{id}") public ResponseEntity<User> getUser(@PathVariable Long id) { User user = userService.getUserById(id); if (user != null) { return ResponseEntity.ok(user); } return ResponseEntity.notFound().build(); } @PutMapping("/{id}") public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) { user.setId(id); User updatedUser = userService.updateUser(user); return ResponseEntity.ok(updatedUser); } @DeleteMapping("/{id}") public ResponseEntity<Void> deleteUser(@PathVariable Long id) { userService.deleteUser(id); return ResponseEntity.ok().build(); } @GetMapping("/cache/{id}") public ResponseEntity<User> getUserWithManualCache(@PathVariable Long id) { String cacheKey = "user:" + id; User user = (User) redisCacheService.getCache(cacheKey); if (user != null) { System.out.println("从Redis缓存获取用户: " + id); return ResponseEntity.ok(user); } user = userService.getUserById(id); if (user != null) { redisCacheService.setCache(cacheKey, user, 300); System.out.println("用户信息已缓存: " + id); } return ResponseEntity.ok(user); } @PostMapping("/cache/clear/{id}") public ResponseEntity<String> clearUserCache(@PathVariable Long id) { String cacheKey = "user:" + id; redisCacheService.deleteCache(cacheKey); return ResponseEntity.ok("用户缓存已清除: " + id); } @PostMapping("/cache/clear-all") public ResponseEntity<String> clearAllUserCache() { redisCacheService.deleteCacheByPattern("user:*"); return ResponseEntity.ok("所有用户缓存已清除"); } }
|
EhCache缓存集成
1. EhCache配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Configuration @EnableCaching public class EhCacheConfig { @Bean public EhCacheManagerFactoryBean ehCacheManagerFactoryBean() { EhCacheManagerFactoryBean factoryBean = new EhCacheManagerFactoryBean(); factoryBean.setConfigLocation(new ClassPathResource("ehcache.xml")); factoryBean.setShared(true); return factoryBean; } @Bean public CacheManager cacheManager() { EhCacheCacheManager cacheManager = new EhCacheCacheManager(); cacheManager.setCacheManager(ehCacheManagerFactoryBean().getObject()); return cacheManager; } }
|
2. EhCache配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"> <cache name="users" maxEntriesLocalHeap="1000" maxEntriesLocalDisk="10000" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </cache> <cache name="products" maxEntriesLocalHeap="500" maxEntriesLocalDisk="5000" eternal="false" timeToIdleSeconds="600" timeToLiveSeconds="1200" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="LFU"> <persistence strategy="localTempSwap"/> </cache> <cache name="orders" maxEntriesLocalHeap="200" maxEntriesLocalDisk="2000" eternal="false" timeToIdleSeconds="180" timeToLiveSeconds="360" diskSpoolBufferSizeMB="20" memoryStoreEvictionPolicy="FIFO"> <persistence strategy="localTempSwap"/> </cache> <defaultCache maxEntriesLocalHeap="100" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" maxEntriesLocalDisk="1000" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU"> <persistence strategy="localTempSwap"/> </defaultCache> </ehcache>
|
3. EhCache缓存服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| @Service public class EhCacheService { @Autowired private CacheManager cacheManager; public Object getCache(String cacheName, String key) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { Cache.ValueWrapper wrapper = cache.get(key); return wrapper != null ? wrapper.get() : null; } return null; } public void setCache(String cacheName, String key, Object value) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.put(key, value); } } public void deleteCache(String cacheName, String key) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.evict(key); } } public void clearAllCache(String cacheName) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.clear(); } } public CacheStatistics getCacheStatistics(String cacheName) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { EhCache ehCache = (EhCache) cache.getNativeCache(); Statistics stats = ehCache.getStatistics(); CacheStatistics statistics = new CacheStatistics(); statistics.setCacheName(cacheName); statistics.setHitCount(stats.getCacheHits()); statistics.setMissCount(stats.getCacheMisses()); statistics.setHitRate(stats.getCacheHitPercentage()); statistics.setSize(stats.getObjectCount()); return statistics; } return null; } public static class CacheStatistics { private String cacheName; private long hitCount; private long missCount; private double hitRate; private long size; public String getCacheName() { return cacheName; } public void setCacheName(String cacheName) { this.cacheName = cacheName; } public long getHitCount() { return hitCount; } public void setHitCount(long hitCount) { this.hitCount = hitCount; } public long getMissCount() { return missCount; } public void setMissCount(long missCount) { this.missCount = missCount; } public double getHitRate() { return hitRate; } public void setHitRate(double hitRate) { this.hitRate = hitRate; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } } }
|
Caffeine缓存集成
1. Caffeine配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| @Configuration @EnableCaching public class CaffeineCacheConfig { @Bean public CacheManager cacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterAccess(5, TimeUnit.MINUTES) .recordStats()); cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(500) .expireAfterWrite(30, TimeUnit.MINUTES) .expireAfterAccess(15, TimeUnit.MINUTES) .recordStats()); cacheManager.setCaffeine(Caffeine.newBuilder() .maximumSize(200) .expireAfterWrite(5, TimeUnit.MINUTES) .expireAfterAccess(2, TimeUnit.MINUTES) .recordStats()); return cacheManager; } @Bean public CacheManager customCacheManager() { CaffeineCacheManager cacheManager = new CaffeineCacheManager(); Map<String, Caffeine<Object, Object>> cacheConfigs = new HashMap<>(); cacheConfigs.put("users", Caffeine.newBuilder() .maximumSize(2000) .expireAfterWrite(1, TimeUnit.HOURS) .expireAfterAccess(30, TimeUnit.MINUTES) .recordStats()); cacheConfigs.put("products", Caffeine.newBuilder() .maximumSize(1000) .expireAfterWrite(30, TimeUnit.MINUTES) .expireAfterAccess(15, TimeUnit.MINUTES) .recordStats()); cacheConfigs.put("orders", Caffeine.newBuilder() .maximumSize(500) .expireAfterWrite(10, TimeUnit.MINUTES) .expireAfterAccess(5, TimeUnit.MINUTES) .recordStats()); cacheManager.setCaffeine(cacheConfigs); return cacheManager; } }
|
2. Caffeine缓存服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| @Service public class CaffeineCacheService { @Autowired private CacheManager cacheManager; public Object getCache(String cacheName, String key) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { Cache.ValueWrapper wrapper = cache.get(key); return wrapper != null ? wrapper.get() : null; } return null; } public void setCache(String cacheName, String key, Object value) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.put(key, value); } } public void deleteCache(String cacheName, String key) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.evict(key); } } public void clearAllCache(String cacheName) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.clear(); } } public CaffeineCacheStatistics getCacheStatistics(String cacheName) { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { com.github.benmanes.caffeine.cache.Cache<Object, Object> caffeineCache = (com.github.benmanes.caffeine.cache.Cache<Object, Object>) cache.getNativeCache(); CaffeineCacheStatistics statistics = new CaffeineCacheStatistics(); statistics.setCacheName(cacheName); statistics.setHitCount(caffeineCache.stats().hitCount()); statistics.setMissCount(caffeineCache.stats().missCount()); statistics.setHitRate(caffeineCache.stats().hitRate()); statistics.setSize(caffeineCache.estimatedSize()); statistics.setEvictionCount(caffeineCache.stats().evictionCount()); return statistics; } return null; } public static class CaffeineCacheStatistics { private String cacheName; private long hitCount; private long missCount; private double hitRate; private long size; private long evictionCount; public String getCacheName() { return cacheName; } public void setCacheName(String cacheName) { this.cacheName = cacheName; } public long getHitCount() { return hitCount; } public void setHitCount(long hitCount) { this.hitCount = hitCount; } public long getMissCount() { return missCount; } public void setMissCount(long missCount) { this.missCount = missCount; } public double getHitRate() { return hitRate; } public void setHitRate(double hitRate) { this.hitRate = hitRate; } public long getSize() { return size; } public void setSize(long size) { this.size = size; } public long getEvictionCount() { return evictionCount; } public void setEvictionCount(long evictionCount) { this.evictionCount = evictionCount; } } }
|
缓存性能优化
1. 缓存预热
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| @Component public class CacheWarmupService { @Autowired private UserService userService; @Autowired private ProductService productService; @Autowired private OrderService orderService; @EventListener(ApplicationReadyEvent.class) public void warmupCache() { System.out.println("开始预热缓存..."); warmupUserCache(); warmupProductCache(); warmupOrderCache(); System.out.println("缓存预热完成"); } private void warmupUserCache() { System.out.println("预热用户缓存..."); List<Long> popularUserIds = getPopularUserIds(); for (Long userId : popularUserIds) { try { userService.getUserById(userId); System.out.println("用户缓存预热: " + userId); } catch (Exception e) { System.err.println("用户缓存预热失败: " + userId + ", " + e.getMessage()); } } } private void warmupProductCache() { System.out.println("预热产品缓存..."); List<Long> popularProductIds = getPopularProductIds(); for (Long productId : popularProductIds) { try { productService.getProductById(productId); System.out.println("产品缓存预热: " + productId); } catch (Exception e) { System.err.println("产品缓存预热失败: " + productId + ", " + e.getMessage()); } } } private void warmupOrderCache() { System.out.println("预热订单缓存..."); List<Long> recentOrderIds = getRecentOrderIds(); for (Long orderId : recentOrderIds) { try { orderService.getOrderById(orderId); System.out.println("订单缓存预热: " + orderId); } catch (Exception e) { System.err.println("订单缓存预热失败: " + orderId + ", " + e.getMessage()); } } } private List<Long> getPopularUserIds() { return Arrays.asList(1L, 2L, 3L, 4L, 5L); } private List<Long> getPopularProductIds() { return Arrays.asList(1L, 2L, 3L, 4L, 5L); } private List<Long> getRecentOrderIds() { return Arrays.asList(1L, 2L, 3L, 4L, 5L); } }
|
2. 缓存监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| @RestController @RequestMapping("/api/cache-monitor") public class CacheMonitorController { @Autowired private EhCacheService ehCacheService; @Autowired private CaffeineCacheService caffeineCacheService; @Autowired private RedisCacheService redisCacheService; @GetMapping("/stats") public ResponseEntity<Map<String, Object>> getCacheStats() { Map<String, Object> stats = new HashMap<>(); Map<String, EhCacheService.CacheStatistics> ehCacheStats = new HashMap<>(); ehCacheStats.put("users", ehCacheService.getCacheStatistics("users")); ehCacheStats.put("products", ehCacheService.getCacheStatistics("products")); ehCacheStats.put("orders", ehCacheService.getCacheStatistics("orders")); stats.put("ehCache", ehCacheStats); Map<String, CaffeineCacheService.CaffeineCacheStatistics> caffeineStats = new HashMap<>(); caffeineStats.put("users", caffeineCacheService.getCacheStatistics("users")); caffeineStats.put("products", caffeineCacheService.getCacheStatistics("products")); caffeineStats.put("orders", caffeineCacheService.getCacheStatistics("orders")); stats.put("caffeine", caffeineStats); Map<String, Object> redisStats = new HashMap<>(); redisStats.put("connected", redisCacheService.hasCache("test")); redisStats.put("memory", getRedisMemoryUsage()); stats.put("redis", redisStats); return ResponseEntity.ok(stats); } @PostMapping("/clear/{cacheName}") public ResponseEntity<String> clearCache(@PathVariable String cacheName) { try { ehCacheService.clearAllCache(cacheName); caffeineCacheService.clearAllCache(cacheName); redisCacheService.deleteCacheByPattern(cacheName + ":*"); return ResponseEntity.ok("缓存清除成功: " + cacheName); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("缓存清除失败: " + e.getMessage()); } } @PostMapping("/clear-all") public ResponseEntity<String> clearAllCache() { try { ehCacheService.clearAllCache("users"); ehCacheService.clearAllCache("products"); ehCacheService.clearAllCache("orders"); caffeineCacheService.clearAllCache("users"); caffeineCacheService.clearAllCache("products"); caffeineCacheService.clearAllCache("orders"); redisCacheService.deleteCacheByPattern("*"); return ResponseEntity.ok("所有缓存清除成功"); } catch (Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("缓存清除失败: " + e.getMessage()); } } private Map<String, Object> getRedisMemoryUsage() { Map<String, Object> memoryInfo = new HashMap<>(); memoryInfo.put("used", "100MB"); memoryInfo.put("peak", "150MB"); memoryInfo.put("fragmentation", "1.2"); return memoryInfo; } }
|
实际项目应用案例
1. 电商系统缓存集成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| @Service public class EcommerceCacheService { @Autowired private UserService userService; @Autowired private ProductService productService; @Autowired private OrderService orderService; @Cacheable(value = "products", key = "#productId", unless = "#result == null") public Product getProductById(Long productId) { System.out.println("从数据库查询商品: " + productId); return productService.findById(productId); } @Cacheable(value = "productList", key = "#category + '_' + #page + '_' + #size") public List<Product> getProductsByCategory(String category, int page, int size) { System.out.println("从数据库查询商品列表: " + category + ", " + page + ", " + size); return productService.findByCategory(category, page, size); } @Cacheable(value = "userCart", key = "#userId") public Cart getUserCart(Long userId) { System.out.println("从数据库查询用户购物车: " + userId); return userService.getCartByUserId(userId); } @CachePut(value = "userCart", key = "#userId") public Cart updateUserCart(Long userId, Cart cart) { System.out.println("更新用户购物车: " + userId); return userService.updateCart(userId, cart); } @CacheEvict(value = "userCart", key = "#userId") public void clearUserCart(Long userId) { System.out.println("清空用户购物车: " + userId); userService.clearCart(userId); } @Cacheable(value = "orders", key = "#orderId") public Order getOrderById(Long orderId) { System.out.println("从数据库查询订单: " + orderId); return orderService.findById(orderId); } @CachePut(value = "orders", key = "#result.id") public Order createOrder(Order order) { System.out.println("创建订单: " + order.getId()); return orderService.save(order); } @CacheEvict(value = "orders", key = "#orderId") public void cancelOrder(Long orderId) { System.out.println("取消订单: " + orderId); orderService.cancelOrder(orderId); } }
|
2. 内容管理系统缓存集成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| @Service public class CmsCacheService { @Autowired private ArticleService articleService; @Autowired private CategoryService categoryService; @Autowired private TagService tagService; @Cacheable(value = "articles", key = "#articleId") public Article getArticleById(Long articleId) { System.out.println("从数据库查询文章: " + articleId); return articleService.findById(articleId); } @Cacheable(value = "articleList", key = "#category + '_' + #page + '_' + #size") public List<Article> getArticlesByCategory(String category, int page, int size) { System.out.println("从数据库查询文章列表: " + category + ", " + page + ", " + size); return articleService.findByCategory(category, page, size); } @Cacheable(value = "popularArticles", key = "#limit") public List<Article> getPopularArticles(int limit) { System.out.println("从数据库查询热门文章: " + limit); return articleService.findPopularArticles(limit); } @CachePut(value = "articles", key = "#article.id") public Article updateArticle(Article article) { System.out.println("更新文章: " + article.getId()); return articleService.save(article); } @CacheEvict(value = "articles", key = "#articleId") public void deleteArticle(Long articleId) { System.out.println("删除文章: " + articleId); articleService.deleteById(articleId); } @Cacheable(value = "categories") public List<Category> getAllCategories() { System.out.println("从数据库查询所有分类"); return categoryService.findAll(); } @Cacheable(value = "tags") public List<Tag> getAllTags() { System.out.println("从数据库查询所有标签"); return tagService.findAll(); } }
|
总结
通过本文的详细介绍和代码实操,我们深入了解了Spring Boot中的缓存框架集成:
核心要点
- Spring Cache抽象:提供统一的缓存操作接口
- 多种缓存实现:支持Redis、EhCache、Caffeine等
- 声明式缓存:通过注解方式管理缓存
- 灵活配置:支持多种缓存策略和配置选项
- 性能优化:缓存预热、监控、统计等功能
最佳实践
- 合理选择缓存实现:根据业务需求选择合适的缓存框架
- 优化缓存策略:设置合适的过期时间和容量限制
- 实现缓存预热:应用启动时预热常用数据
- 监控缓存性能:持续监控缓存命中率和性能指标
- 处理缓存一致性:确保缓存与数据库数据的一致性
注意事项
- 缓存键的设计要合理,避免冲突
- 注意缓存的内存使用,避免内存溢出
- 实现缓存降级策略,确保系统稳定性
- 定期清理过期缓存,释放内存空间
- 监控缓存性能,及时调整缓存策略
掌握Spring Boot缓存框架的集成和使用,将大大提升应用的性能和用户体验。