SpringBoot @Cacheable 缓存不生效的问题
背景
Springboot + CaffeineCache + 使用@Cacheable注解
请求查询一个方法,因为数据变化频率低,查询频率高,于是使用缓存,并使用注解。
但发现用了 @Cacheable 这个注解,发现并没有生效。
代码是这样子的
***ServiceImpl.java
public void getUser(UserFo fo){
// 省略
// ....
// 在这里希望使用缓存,因为这个方法会被频繁调用,那也会频繁访问数据库,就大可不必,没有太多的必要
User user = getUserInfo(fo.getUsername());
// 省略
// ....
}
@Cacheable(value = "common", key="#username")
public User getUserInfo(String username){
// 省略
// ....
}
***CacheConfig.java
// 在这个类里面,写了两个 cache 超时机制,都是放在了 CacheManager
@Configuration
public class CacheConfig {
/**
* 默认的超时时间
*/
@Value("${caching.expire.duration:60}")
private int duration;
@Value("${caching.expire.longDuration:60}")
private int longDuration;
@Value("${caching.maximumSize:1000}")
private int maximumSize;
@Bean
public CacheManager cacheManager() {
CaffeineCache cache = buildCache("common", duration);
CaffeineCache longDurationCache = buildCache("longDurationCache", longDuration);
SimpleCacheManager manager = new SimpleCacheManager();
manager.setCaches(Arrays.asList(cache, longDurationCache));
return manager;
}
private CaffeineCache buildCache(String name, int secondsToExpire) {
return new CaffeineCache(name, Caffeine.newBuilder()
.expireAfterWrite(secondsToExpire, TimeUnit.SECONDS)
.maximumSize(maximumSize)
.build());
}
}
方法如上,搞了很久,一开始还以为是没有缓存定义的 key 哪里有问题 —— 不是
然后,又以为是在启动类没有加 @EnableCaching —— 不是
后来终于找到了正解:
一个方法A调同一个类里的另一个有缓存注解的方法B,这样是不走缓存的。
原因: 使用@Cacheable添加缓存实际上就是使用动态代理做的,在代理的方法前后做缓存的相应处理。这样一来,单独的去调方法B是有缓存的,但是如果调方法A,A里面再去调B方法,哪怕B方法配置了缓存,也是不会生效的。
解决方法:
- a、不使用注解的方式,直接取 Ehcache 的 CacheManger 对象,把需要缓存的数据放到里面,类似于使用 Map,缓存的逻辑自己控制
- b、把方法A和方法B放到两个不同的类里面,例如:如果两个方法都在service接口里,把方法B放到另一个service里面,这样A方法里调B方法,就可以使用B方法的缓存
一开始就是按方法一去写的,是已经可用了的,但感觉使用注解会更加方便,于是乎就改成使用注解,想不到使用注解,注出了问题,缓存根本不生效。于是各种找原因,也好在终于是找到了。
再附上,直接使用 CacheManager 对象,通过 autowired 注入方式的方案:
@Autowired
CacheManager cacheManager;
// @Cacheable(value = "common", key="#username") // 因为这个方法是被同个类的另外一个方法调用的,所以在这个方法上加注解是无效的。emmmm,这种情况,只能使用CacheManager 这种方案
public UserVO getUserInfo(String username) {
// 这是在使用注解时做的调试,每次都进来这里,说明缓存没有生效。
// if (null != cacheManager.getCache("common").get(username)) {
// Object common = cacheManager.getCache("common").get("login-user-info-" + username).get();
// log.warn("cache !!!============ {}", common);
// } else {
// log.warn("no cache !!!============");
// }
//
// ObjectResponse<UserVO> response = rbacClient.findByLdapId(username);
// return Optional.ofNullable(response)
// .map(resp -> resp.getData())
// .orElse(null);
String cacheKey = "login-user-info:" + username;
Cache cache = cacheManager.getCache("common");
UserVO user = (UserVO) Optional.ofNullable(cache)
.map(c -> c.get(cacheKey))
.map(wapper -> {
Object o = wapper.get();
log.debug("fetch user from cache: username: {}, userInfo: {}", username, o);
return o;
}).orElseGet(() -> {
ObjectResponse<UserVO> response = rbacClient.findByLdapId(username);
return Optional.ofNullable(response)
.map(resp -> resp.getData())
.map(data -> {
cache.put(cacheKey, data);
return data;
}).orElse(null);
});
return user;
}
坑了自己一把,记录一下。。。。