Spring's Bean internal method call cannot use AOP facet (CacheAble annotation is invalid)
Preface
Today, in the process of using Spring cache's Cacheable annotation, we encountered a problem of invalidation of Cacheable annotation. The reason for checking the problem is that Spring's Cacheable annotation is implemented based on Spring AOP, but when methods inside the class call each other, they will not be blocked by Spring AOP, so the Cacheable annotation of the called method is invalid. It is hereby recorded.
Problem recurrence
@Service public class UserServiceImpl{ @Override public User detail(Long id) { // Verification information 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); } }
The Cacheable annotation is invalid when using this.selectById in the above code. The solution is as follows:
- Write a tool class SpringContextUtil to implement the ApplicationContextAware interface
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); } }
- Inject ApplicationContext into SpringContextUtil when Spring Boot starts
public class AuthServiceApplication { public static void main(String[] args) { SpringContextUtil springContextUtil = new SpringContextUtil(); ApplicationContext applicationContext = SpringApplication.run(AuthServiceApplication.class, args); springContextUtil.setApplicationContext(applicationContext); } }
- Use in UserServiceImpl method
@Service public class UserServiceImpl{ @Override public User detail(Long id) { // Verification information if (id == null || id == 0) { return ApiResult.instance().fail(UserResultEnum.USER_ID_NULL); } //Inject the current Bean so that the internal method of the call is also intercepted by spring AOP 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); } }
This can solve the problem that the internal method calls of Bean are not blocked by Spring AOP