今天在使用Spring cache的Cacheable注解的过程中遇见了一个Cacheable注解失效的问题,检查问题发生的原因是因为Spring的Cacheable注解是基于Spring AOP实现的,但是类内部方法互相调用时不会被Spring AOP拦截的,所以导致被调用方法的Cacheable注解失效,特此记录。
问题复现
@Service
public class UserServiceImpl{
@Override
public User detail(Long id) {
// 校验信息
if (id == null || id == 0) {
return ApiResult.instance().fail(UserResultEnum.USER_ID_NULL);
}
User user = this.selectById(id);
if (user == null) {
return ApiResult.instance().fail(UserResultEnum.USER_NULL);
}
return user;
}
@Override
@Cacheable(value = "user",condition = "#id != null", key = "‘user‘.concat(#id.toString())")
public User selectById(Serializable id){
return super.selectById(id);
}
}
上述代码在使用this.selectById的时候Cacheable注解是无效的,解决办法如下:
- 写一个工具类SpringContextUtil实现ApplicationContextAware接口
public class SpringContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext){
SpringContextUtil.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
public static Object getBean(Class var1) throws BeansException {
return applicationContext.getBean(var1);
}
}
- 在Spring Boot启动的时候将ApplicationContext注入SpringContextUtil
public class AuthServiceApplication {
public static void main(String[] args) {
SpringContextUtil springContextUtil = new SpringContextUtil();
ApplicationContext applicationContext = SpringApplication.run(AuthServiceApplication.class, args);
springContextUtil.setApplicationContext(applicationContext);
}
}
- 在UserServiceImpl方法中使用
@Service
public class UserServiceImpl{
@Override
public User detail(Long id) {
// 校验信息
if (id == null || id == 0) {
return ApiResult.instance().fail(UserResultEnum.USER_ID_NULL);
}
//注入当前Bean使得调用内部方法也被SpringAOP拦截
IUserService userService = (IUserService) SpringContextUtil.getBean(this.getClass());
User user = userService.selectById(id);
if (user == null) {
return ApiResult.instance().fail(UserResultEnum.USER_NULL);
}
return user;
}
@Override
@Cacheable(value = "user",condition = "#id != null", key = "‘user‘.concat(#id.toString())")
public User selectById(Serializable id){
return super.selectById(id);
}
}
这样就可以解决Bean内部方法调用不被Spring AOP拦截的问题