SpringBoot整合SpringCache使用缓存
文章目录
- SpringBoot整合SpringCache使用缓存
- 1.介绍
- 2.SpringBoot整合
- 1.导入xml依赖
- 2.配置yml
- 3.使用@EnableCaching启用SpringCache
- 4.@Cacheable
- 5.@CachePut
- 6.@CacheEvict
- 7. @Caching
- 8.@CacheConfig
- 3.其他属性配置
- 1.`keyGenerator` 属性
- 2. `cacheManager` 属性
- 3.`cacheResolver` 属性
- 4.CacheManagerCustomizer
1.介绍
Spring Cache 提供了 Cache
和 CacheManager
接口来统一管理不同的缓存技术。Cache
是缓存的抽象,CacheManager
负责管理多个 Cache
实例。Spring Cache 支持多种缓存实现,包括:
- ConcurrentHashMap:默认的缓存实现,适用于简单的本地缓存。
- Redis:基于 Redis 的分布式缓存,适用于高并发场景。
- Ehcache:符合 JSR-107 标准的缓存实现,支持二级缓存。
- Caffeine:基于 Java 8 的高性能缓存库,适用于需要高性能的场景。
- JSR-107:支持 JSR-107 标准的缓存实现。
2.SpringBoot整合
本文基于springboot2.7版本测试
1.导入xml依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
2.配置yml
spring:cache:cache-names: usertype: redisredis:#缓存前缀key-prefix: moshangshang_#是否启用缓存统计信息。enable-statistics: false#是否允许缓存 null 值。cache-null-values: true#写入 Redis 时是否使用 key prefix。use-key-prefix: trueredis:port: 6379host: 127.0.0.1password: rootlettuce:pool:max-active: 20 #连接池最大连接数(使用负值表示没有限制)max-idle: 8 #连接池中的最大空闲连接min-idle: 5 # 连接池中的最小空闲连接timeout: 6000 #连接超时时长(毫秒)
如果cache-null-values:属性启用不能缓存null值,则缓存null时会抛出下方异常
java.lang.IllegalArgumentException: Cache 'user' does not allow 'null' values. Avoid storing null via '@Cacheable(unless="#result == null")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.
cache-names属性说明:
用于管理全的缓存key的全局配置,多个用逗号分割,比如 cache-names: user; use-key-prefix: false,则表示 @Cacheable(cacheNames = "user“)之类的注解不会使用key-prefix指定的缓存前缀,未配置的缓存名称则采用默认全局配置
3.使用@EnableCaching启用SpringCache
@SpringBootApplication
@EnableCaching
public class CacheApplication {public static void main(String[] args) {SpringApplication.run(CacheApplication.class, args);}
}
4.@Cacheable
@Cacheable 用于标记方法或类,表示该方法的返回值可以被缓存。
当方法执行前,Spring 会检查缓存中是否存在相同 key 的缓存元素,如果存在则直接返回,否则执行方法并将结果存入缓存。
@Cacheable 的方法必须为 public:如果方法不是 public 的,Spring 无法通过代理来访问缓存。
- value 或 cacheNames:指定缓存的名称,可以是单个字符串或字符串数组。
- key:指定缓存的键,可以使用 SpEL 表达式来定义。
- condition:指定缓存的条件,只有当条件为 true 时,才会从缓存中获取结果。
- unless:指定不将结果放入缓存的条件,即使结果存在,也不会被缓存。
- sync:是否使用同步方式获取缓存,避免多个线程同时执行方法。
- 在某些场景下,需要确保缓存和数据库的一致性,可以使用 @Cacheable 的 sync 属性来启用同步更新。且在多线程环境下确保只有一个线程执行查询。
/*** 根据id查询用户信息* 生成的key为moshangshang_user::38*/@GetMapping("/query/{id}")@Cacheable(cacheNames = "user",key = "#id",unless = "#result == null")public User getById(@PathVariable Long id){return userService.getById(id);}
5.@CachePut
@CachePut 用于标记方法,表示每次调用该方法时都会执行并存入缓存。
它总是会执行方法,并将结果添加到缓存中,不会检查缓存中是否存在相同 key 的缓存元素。
- value 或 cacheNames:指定缓存的名称,可以是单个字符串或字符串数组。
- key:指定缓存的键,可以使用 SpEL 表达式来定义。
- condition:指定缓存的条件,只有当条件为 true 时,才会从缓存中获取结果。
- unless:指定不将结果放入缓存的条件,即使结果存在,也不会被缓存。
@PostMapping("/save")@CachePut( key = "#user.id")public User updateUser(User user) {userService.saveOrUpdate(user);return user;}
6.@CacheEvict
@CacheEvict 用于标记方法,表示该方法执行时会清除缓存中的数据。
@CacheEvict 在方法执行期间抛出异常不会清空缓存:如果方法执行过程中抛出异常,@CacheEvict 的 allEntries 属性不会生效。
它可以用于删除缓存中的所有键值对,也可以用于清除特定的 key。
- value 或 cacheNames:指定缓存的名称,可以是单个字符串或字符串数组。
- key:指定缓存的键,可以使用 SpEL 表达式来定义。
- condition:指定缓存的条件,只有当条件为 true 时,才会从缓存中获取结果。
- beforeInvocation:是否在方法执行前清除缓存,为 true 时在方法执行前清除缓存。
- allEntries:是否清除所有缓存条目,为 true 时清除所有缓存。
/*** @CacheEvict 在方法执行期间抛出异常不会清空缓存:如果方法执行过程中抛出异常,@CacheEvict 的 allEntries 属性不会生效。* @CacheEvict 用于标记方法,表示该方法执行时会清除缓存中的数据。* 它可以用于删除缓存中的所有键值对,也可以用于清除特定的 key。* value 或 cacheNames:指定要清除的缓存名称。* key:指定要清除的缓存键,可以使用 SpEL 表达式来定义。* allEntries:是否清除所有缓存条目,为 true 时清除所有缓存。* beforeInvocation:是否在方法执行前清除缓存,为 true 时在方法执行前清除缓存。* condition:指定清除缓存的条件,只有当条件为 true 时,才会清除缓存。*/@GetMapping("/delete/{id}")@CacheEvict(key = "#id", allEntries = false)public void deleteUser(@PathVariable Long id) {userService.removeById(id);}
7. @Caching
@Caching 是一个组合注解,可以同时应用多个其他注解,表示该方法会同时执行 @Cacheable、@CachePut 和 @CacheEvict 的操作。
@GetMapping("/save/caching")@Caching(cacheable = @Cacheable( key = "#user.id"),put = @CachePut( key = "#user.id"),evict = @CacheEvict( key = "#user.id"))public User saveUser(User user) {userService.save(user);return user;}
8.@CacheConfig
@CacheConfig 用于在类上设置公共的缓存配置,避免在每个方法上重复配置。
/*** @CacheConfig 用于在类上设置公共的缓存配置,避免在每个方法上重复配置。*/
@RestController
@AllArgsConstructor
@RequestMapping("cache")
@CacheConfig(cacheNames = "user")
public class CacheController {private final IUserService userService;@GetMapping("/query/{id}")@Cacheable(key = "#id",unless = "#result == null")public User getById(@PathVariable Long id){return userService.getById(id);}
}
3.其他属性配置
1.keyGenerator
属性
keyGenerator
属性用于指定默认的键生成器(Key Generator)。如果在方法上未显式指定 key
属性,则使用该属性值作为默认的键生成器。
1.配置生成器
@Configuration
public class CacheConfig {@Bean(name = "customKeyGenerator")public KeyGenerator keyGenerator() {return (target, method, params) -> method.getName() + "[" + Arrays.asList(params) + "]";}
}
等同于
@Bean(name = "customKeyGenerator")public KeyGenerator keyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {return method.getName() + "[" + Arrays.asList(params) + "]";}};}
2.使用
生成的key为moshangshang_user::getById[[39]]
@Cacheable(unless = "#result == null",keyGenerator = "customKeyGenerator")public User getById(@PathVariable Long id){return userService.getById(id);}
2. cacheManager
属性
cacheManager
属性用于指定当前使用的 CacheManager
实现类的名称。CacheManager
是 Spring 定义的一个接口,用于管理缓存(Cache)的创建和配置。Spring 提供了多种 CacheManager
的实现,例如 ConcurrentMapCacheManager
、EhCacheCacheManager
、CaffeineCacheManager
等。通过设置 cacheManager
属性,可以指定使用哪种缓存管理器来管理缓存。
创建自定义的缓存管理器
@Configuration
public class CacheConfig {@Beanpublic ConcurrentMapCacheManager mapCacheManager() {return new ConcurrentMapCacheManager("user-map","user");}}
cacheManager()
方法返回了一个 ConcurrentMapCacheManager
实例,并且指定了缓存名称。这个 CacheManager
将被用于管理名为 指定的缓存。
/*** 执行的是mapCacheManager的缓存管理器*/@GetMapping("/manger/map/query/{id}")@Cacheable(cacheManager = "mapCacheManager")public User getRedisMangerById(@PathVariable Long id){return userService.getById(id);}
3.cacheResolver
属性
cacheResolver
属性用于指定一个自定义的 CacheResolver
实现。默认情况下,Spring 使用 SimpleCacheResolver
来解析缓存操作。通过自定义 CacheResolver
,可以实现更复杂的缓存逻辑,例如根据方法名动态选择缓存名称或缓存管理器。
cacheManager
和cacheResolver
是互斥的:如果同时指定了cacheManager
和cacheResolver
,Spring 会抛出异常,因为CacheResolver
的实现会忽略自定义的CacheManager
。- 自定义
CacheResolver
的灵活性:通过自定义CacheResolver
,可以实现更灵活的缓存管理,例如根据方法名、参数或上下文动态选择缓存名称或缓存管理器 。 - Spring 4.1 及以上版本:从 Spring 4.1 开始,
@Cacheable
、@CachePut
、@CacheEvict
等注解的value
属性不再是强制性的,因为CacheResolver
可以提供缓存名称信息
自定义缓存解析器
getById方法取user缓存名称下数据,其他取user-map下数据
public class CustomCacheResolver implements CacheResolver {private final ConcurrentMapCacheManager concurrentMapCacheManager;private final RedisCacheManager redisCacheManager;public CustomCacheResolver(ConcurrentMapCacheManager concurrentMapCacheManager, RedisCacheManager redisCacheManager) {this.concurrentMapCacheManager = concurrentMapCacheManager;this.redisCacheManager = redisCacheManager;}@Overridepublic Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) {Collection<Cache> caches = new ArrayList<>();if (context.getTarget().getClass() == CacheController.class) {if (context.getMethod().getName().equals("getRedisById")) {caches.add(redisCacheManager.getCache("user"));}else {caches.add(concurrentMapCacheManager.getCache("user-map"));}}return caches;}
}
配置自定义缓存管理器并注册缓存解析器
配置了自定义的CacheManager会导致yml里面的相关配置失效(任何一个都会,比如指定map的缓存管理器,yml配redis,则redis的配置也不生效)
@Beanpublic ConcurrentMapCacheManager mapCacheManager() {return new ConcurrentMapCacheManager("user-map","user");}@Primary@Beanpublic RedisCacheManager redisCacheManager(RedisTemplate<String, Object> redisTemplate) {return RedisCacheManager.builder(Objects.requireNonNull(redisTemplate.getConnectionFactory())).cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 设置默认缓存过期时间为10分钟.disableCachingNullValues()) // 禁用缓存空值.withInitialCacheConfigurations(initialCacheConfigurations()) // 设置特定缓存的配置.build();}private Map<String, RedisCacheConfiguration> initialCacheConfigurations() {Map<String, RedisCacheConfiguration> initialConfigurations = new HashMap<>();// 设置特定缓存的过期时间initialConfigurations.put("user", RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1)) // 设置特定缓存的过期时间为1小时.disableCachingNullValues());return initialConfigurations;}@Beanpublic CacheResolver customCacheResolver(ConcurrentMapCacheManager concurrentMapCacheManager,RedisCacheManager redisCacheManager) {return new CustomCacheResolver(concurrentMapCacheManager,redisCacheManager);}
测试
/*** 执行的是RedisCacheManager的缓存管理器*/@GetMapping("/resolver/redis/query/{id}")@Cacheable(unless = "#result == null",cacheResolver = "customCacheResolver")public User getRedisById(@PathVariable Long id){return userService.getById(id);}/*** 执行的是ConcurrentMapCacheManager的缓存管理器*/@GetMapping("/resolver/map/query/{id}")@Cacheable(cacheNames = "user-map",unless = "#result == null",cacheResolver = "customCacheResolver")public User getMapCacheById(@PathVariable Long id){return userService.getById(id);}
4.CacheManagerCustomizer
CacheManagerCustomizer
是一个用于在缓存管理器初始化之前对其进行自定义配置的接口。通过实现该接口的 Bean,可以对缓存管理器进行定制,例如设置缓存名称、是否允许缓存空值、设置缓存过期时间等。
- 自定义缓存配置:
CacheManagerCustomizer
允许在缓存管理器初始化之前对缓存进行配置,例如设置缓存名称、过期时间、序列化方式等。这使得开发者可以针对不同的缓存需求进行灵活配置。 - 覆盖默认配置:如果使用了
CacheManagerCustomizer
,那么application.yml
或application.properties
中的缓存配置将不会生效,因为CacheManagerCustomizer
会覆盖默认的配置 。 - 支持多种缓存类型:
CacheManagerCustomizer
不仅适用于ConcurrentMapCacheManager
,还可以用于其他类型的缓存管理器,如RedisCacheManager
、CaffeineCacheManager
等。通过实现CacheManagerCustomizer
接口,可以对不同类型的缓存管理器进行统一的配置 。 - 提供回调机制:
CacheManagerCustomizer
提供了一个customize
方法,该方法会在缓存管理器初始化之前被调用,允许开发者对缓存管理器进行定制。例如,可以设置缓存名称、允许或禁止缓存空值等 。
@Bean
public CacheManagerCustomizer<ConcurrentMapCacheManager> cacheManagerCustomizer() {return new CacheManagerCustomizer<ConcurrentMapCacheManager>() {@Overridepublic void customize(ConcurrentMapCacheManager cacheManager) {cacheManager.setCacheNames(Arrays.asList("user"));cacheManager.setAllowNullValues(false); // 禁用缓存空值}};
}@Beanpublic RedisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {return (builder) -> {builder.cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(10)) // 默认过期时间为 10 分钟.disableCachingNullValues()); // 禁用缓存空值};}
如果配置了自定义的缓存管理器(redisCacheManager),则CacheManagerCustomizer将不生效