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: user
type: redis
redis:
#缓存前缀
key-prefix: moshangshang_
#是否启用缓存统计信息。
enable-statistics: false
#是否允许缓存 null 值。
cache-null-values: true
#写入 redis 时是否使用 key prefix。
use-key-prefix: true
redis:
port: 6379
host: 127.0.0.1
password: root
lettuce:
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() {
@override
public 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 {
@bean
public 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;
}
@override
public 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的配置也不生效)
@bean
public concurrentmapcachemanager mapcachemanager() {
return new concurrentmapcachemanager("user-map","user");
}
@primary
@bean
public 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;
}
@bean
public 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>() {
@override
public void customize(concurrentmapcachemanager cachemanager) {
cachemanager.setcachenames(arrays.aslist("user"));
cachemanager.setallownullvalues(false); // 禁用缓存空值
}
};
}
@bean
public rediscachemanagerbuildercustomizer rediscachemanagerbuildercustomizer() {
return (builder) -> {
builder.cachedefaults(
rediscacheconfiguration.defaultcacheconfig()
.entryttl(duration.ofminutes(10)) // 默认过期时间为 10 分钟
.disablecachingnullvalues()); // 禁用缓存空值
};
}
如果配置了自定义的缓存管理器(rediscachemanager),则cachemanagercustomizer将不生效
到此这篇关于springboot整合springcache缓存的实现示例的文章就介绍到这了,更多相关springboot springcache缓存内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论