解决springCache配置中踩的坑

网友投稿 727 2022-09-07


解决springCache配置中踩的坑

目录springCache配置中踩的坑先附上正确的配置springCache配置及一些问题的解决配置@Cacheable参数@CacheEvict 参数@CachePut 参数

springCache配置中踩的坑

项目基于SpringBoot,使用了SpringCache。

早先在网上找了一份SpringCache的配置,后来由于需要使用到自定义序列化方法,注入一个自定义的序列化类。但是在后来发现自定义的序列化类始终没有调用,后来查看源码后终于发现了原因

先附上正确的配置

@Bean

public CacheManager cacheManager(RedisConnectionFactory factory, SessionSerializer serializer) {

logger.debug("生成缓存管理器");

logger.debug("注入的序列化工具={}", serializer);

RedisSerializationContext.SerializationPair pair = RedisSerializationContext.SerializationPair.fromSerializer(serializer);

logger.debug("生成的cache序列化工具={}", pair);

RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一个默认配置,通过config对象即可对缓存进行自定义配置

config = config.entryTtl(Duration.ofMinutes(10)) // 设置缓存的默认过期时间,也是使用Duration设置

.serializeValuesWith(pair)

// .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))

.disableCachingNullValues()

; // 不缓存空值

logger.debug("初始化完成的config={}", config);

// 设置一个初始化的缓存空间set集合

Set cacheNames = new HashSet<>();

cacheNames.add(CACHE_NAME);

return RedisCacheManager.builder(new CusTtlRedisCacheWriter(factory)) // 使用自定义的缓存配置初始化一个cacheManager

.cacheDefaults(config)//这一句必须要最先执行,否则实际运行时使用的是defaultConfig

.initialCacheNames(cacheNames)

// .withInitialCacheConfigurations(configMap)

// .transactionAware()

.build();

}

重要在于最后一行return的时候,早先的找到的资料说initialCacheNames方法一定要先执行,否则就会巴拉巴拉~~~,,结果就掉坑了

如果initialCacheNames方法先执行的话,实际上CacheManager里使用的是DefaultConfig,里面的序列化方式也就是Jdk序列化,后面在调用cacheDefaults也没有用了。

所有,cacheDetaults方法一定要先执行

springCache配置及一些问题的解决

配置

1. applicationContext.xml

xmlns:cache="http://springframework.org/schema/cache"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsdhttp://springframework.org/schema/cache http://springframework.org/schema/cache/spring-cache.xsd">

  

p:name="default"/>

p:name="activityCache"/>

p:name="awardsCache"/>

Spring内部默认使用 ConcurrentHashMap 来存储, 配置中的 activityCache awardsCache 就是一个一个的 ConcurrentHashMap 对象的名字. 另外 spring还支持使用 EHCache 来存储缓存.

2. 在service的实现类上加上 @Cacheable

//@Service

//public class LotteryActivityServiceImpl implements LotteryActivityService

@Cacheable(value = "activityCache", key = "#shortName")

public LotteryActivity findByShortName(String shortName) {

log.info("query activity : {} from database.", shortName);

return activityRepository.findByShortName(shortName);

}

@Cacheable参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

在需要清除缓存的方法上加上@CacheEvict

@CacheEvict(value="activityCache", allEntries = true, beforeInvocation = true)

public void cleanActivityCache(String shortName) {

log.info("cleaned cache activity : {}", shortName);

}

@CacheEvict 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @CachEvict(value=”testcache”,key=”#userName”

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”)

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

当需要保证方法被调用,又希望结果被缓存, 可以使用@CachePut

@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存

public Account updateAccount(Account account) {

return updateDB(account);

}

@CachePut 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注解最好加在实现类而不是接口的方法上

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.

带有@Cache* 注解的方法不能被定义在调用该方法的类里, 比如 UserController要调用 findUserByName(String name), 且该方法有 @Cacheabele注解, 那么该方法就不能被定义在 UserController中

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case.

@Cache*注解要加在 public 方法上

When using proxies, you should apply the @Cache* annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settinhttp://gs. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.

xmlns:cache="http://springframework.org/schema/cache"

xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsdhttp://springframework.org/schema/cache http://springframework.org/schema/cache/spring-cache.xsd">

  

p:name="default"/>

p:name="activityCache"/>

p:name="awardsCache"/>

Spring内部默认使用 ConcurrentHashMap 来存储, 配置中的 activityCache awardsCache 就是一个一个的 ConcurrentHashMap 对象的名字. 另外 spring还支持使用 EHCache 来存储缓存.

2. 在service的实现类上加上 @Cacheable

//@Service

//public class LotteryActivityServiceImpl implements LotteryActivityService

@Cacheable(value = "activityCache", key = "#shortName")

public LotteryActivity findByShortName(String shortName) {

log.info("query activity : {} from database.", shortName);

return activityRepository.findByShortName(shortName);

}

@Cacheable参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

在需要清除缓存的方法上加上@CacheEvict

@CacheEvict(value="activityCache", allEntries = true, beforeInvocation = true)

public void cleanActivityCache(String shortName) {

log.info("cleaned cache activity : {}", shortName);

}

@CacheEvict 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @CachEvict(value=”testcache”,key=”#userName”

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”)

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

当需要保证方法被调用,又希望结果被缓存, 可以使用@CachePut

@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存

public Account updateAccount(Account account) {

return updateDB(account);

}

@CachePut 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注解最好加在实现类而不是接口的方法上

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.

带有@Cache* 注解的方法不能被定义在调用该方法的类里, 比如 UserController要调用 findUserByName(String name), 且该方法有 @Cacheabele注解, 那么该方法就不能被定义在 UserController中

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case.

@Cache*注解要加在 public 方法上

When using proxies, you should apply the @Cache* annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settinhttp://gs. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.

p:name="default"/>

p:name="activityCache"/>

p:name="awardsCache"/>

Spring内部默认使用 ConcurrentHashMap 来存储, 配置中的 activityCache awardsCache 就是一个一个的 ConcurrentHashMap 对象的名字. 另外 spring还支持使用 EHCache 来存储缓存.

2. 在service的实现类上加上 @Cacheable

//@Service

//public class LotteryActivityServiceImpl implements LotteryActivityService

@Cacheable(value = "activityCache", key = "#shortName")

public LotteryActivity findByShortName(String shortName) {

log.info("query activity : {} from database.", shortName);

return activityRepository.findByShortName(shortName);

}

@Cacheable参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

在需要清除缓存的方法上加上@CacheEvict

@CacheEvict(value="activityCache", allEntries = true, beforeInvocation = true)

public void cleanActivityCache(String shortName) {

log.info("cleaned cache activity : {}", shortName);

}

@CacheEvict 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @CachEvict(value=”testcache”,key=”#userName”

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”)

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

当需要保证方法被调用,又希望结果被缓存, 可以使用@CachePut

@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存

public Account updateAccount(Account account) {

return updateDB(account);

}

@CachePut 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注解最好加在实现类而不是接口的方法上

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.

带有@Cache* 注解的方法不能被定义在调用该方法的类里, 比如 UserController要调用 findUserByName(String name), 且该方法有 @Cacheabele注解, 那么该方法就不能被定义在 UserController中

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case.

@Cache*注解要加在 public 方法上

When using proxies, you should apply the @Cache* annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settinhttp://gs. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.

p:name="activityCache"/>

p:name="awardsCache"/>

p:name="awardsCache"/>

Spring内部默认使用 ConcurrentHashMap 来存储, 配置中的 activityCache awardsCache 就是一个一个的 ConcurrentHashMap 对象的名字. 另外 spring还支持使用 EHCache 来存储缓存.

2. 在service的实现类上加上 @Cacheable

//@Service

//public class LotteryActivityServiceImpl implements LotteryActivityService

@Cacheable(value = "activityCache", key = "#shortName")

public LotteryActivity findByShortName(String shortName) {

log.info("query activity : {} from database.", shortName);

return activityRepository.findByShortName(shortName);

}

@Cacheable参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

在需要清除缓存的方法上加上@CacheEvict

@CacheEvict(value="activityCache", allEntries = true, beforeInvocation = true)

public void cleanActivityCache(String shortName) {

log.info("cleaned cache activity : {}", shortName);

}

@CacheEvict 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @CachEvict(value=”testcache”,key=”#userName”

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 例如: @CachEvict(value=”testcache”, condition=”#userName.length()>2”)

allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 例如: @CachEvict(value=”testcache”,allEntries=true)

beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 例如: @CachEvict(value=”testcache”,beforeInvocation=true)

当需要保证方法被调用,又希望结果被缓存, 可以使用@CachePut

@CachePut(value="accountCache",key="#account.getName()")// 更新 accountCache 缓存

public Account updateAccount(Account account) {

return updateDB(account);

}

@CachePut 参数

value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个 例如: @Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}

key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 例如: @Cacheable(value=”testcache”,key=”#userName”)

condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 例如: @Cacheable(value=”testcache”,condition=”#userName.length()>2”)

注解最好加在实现类而不是接口的方法上

Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the @Cache* annotation, as opposed to annotating interfaces. You certainly can place the @Cache* annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that java annotations are not inherited from interfaces means that if you are using class-based proxies (proxy-target-class="true") or the weaving-based aspect (mode="aspectj"), then the caching settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a caching proxy, which would be decidedly bad.

带有@Cache* 注解的方法不能被定义在调用该方法的类里, 比如 UserController要调用 findUserByName(String name), 且该方法有 @Cacheabele注解, 那么该方法就不能被定义在 UserController中

In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual caching at runtime even if the invoked method is marked with @Cacheable - considering using the aspectj mode in this case.

@Cache*注解要加在 public 方法上

When using proxies, you should apply the @Cache* annotations only to methods with public visibility. If you do annotate protected, private or package-visible methods with these annotations, no error is raised, but the annotated method does not exhibit the configured caching settinhttp://gs. Consider the use of AspectJ (see below) if you need to annotate non-public methods as it changes the bytecode itself.


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:适用于初学者学习的Python正则表达式(python正则表达式或者用法)
下一篇:Python内置的4个重要基本数据结构:列表、元组、字典和集合
相关文章

 发表评论

暂时没有评论,来抢沙发吧~