前言

今天在使用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拦截的问题

Spring的Bean内部方法调用无法使用AOP切面(CacheAble注解失效)的更多相关文章

  1. Spring,为内部方法新起一个事务,此处应有坑。

    事务的作用,使我们操作能够连贯起来.而spring则是提供了一个更简单的方法,只要使用 @Transactional 一个注解,就可以保证操作的连贯性了. 普通用法,稍后再说,这里要说的是: 在最外面 ...

  2. 普通Java类获取Spring的Bean的方法

    普通Java类获取Spring的Bean的方法 在SSH集成的前提下.某些情况我们需要在Action以外的类中来获得Spring所管理的Service对象. 之前我在网上找了好几好久都没有找到合适的方 ...

  3. Spring AOP无法拦截内部方法调用

    当在同一个类中,A方法调用B方法时,AOP无法工作的问题 假设一个接口里面有两个方法: package demo.long; public interface CustomerService { pu ...

  4. Spring 内部方法调用失效问题(AOP)

    AOP使用的是动态代理的机制,它会给类生成一个代理类,事务的相关操作都在代理类上完成.内部方式使用this调用方式时,使用的是实例调用,并没有通过代理类调用方法,所以会导致事务失效. 解决办法 方式一 ...

  5. SpringBoot 内部方法调用,事务不起作用的原因及解决办法

    在做业务开发时,遇到了一个事务不起作用的问题.大概流程是这样的,方法内部的定时任务调用了一个带事务的方法,失败后事务没有回滚.查阅资料后,问题得到解决,记录下来分享给大家. 场景 我在这里模拟一个场景 ...

  6. 菜鸟学习Spring——60s配置XML方法实现简单AOP

    一.概述. 上一篇博客讲述了用注解的形式实现AOP现在讲述另外一种AOP实现的方式利用XML来实现AOP. 二.代码演示. 准备工作参照上一篇博客<菜鸟学习Spring--60s使用annota ...

  7. 普通java类获取spring容器bean的方法

    很多时候,我们在普通的java类中需要获取spring的bean来做操作,比如,在线程中,我们需要操作数据库,直接通过spring的bean中构建的service就可以完成.无需自己写链接..有时候有 ...

  8. 使用Spring实例化Bean的方法以及Bean取别名

    一.通过构造方法实例化Bean bean中加构造方法 public class Bean1 { public Bean1() { System.out.println("Bean1构造方法. ...

  9. AOP方法增强自身内部方法调用无效 SpringCache 例子

    开启注解@EnableCaChing,配置CacheManager,结合注解@Cacheable,@CacheEvit,@CachePut对数据进行缓存操作 缺点:内部调用,非Public方法上使用注 ...

随机推荐

  1. 0_Simple__fp16ScalarProduct

    使用cuda内置无符号整数结构(__half2)及其汇编函数,计算两个向量的内积. 源代码: #include <cstdio> #include <cstdlib> #inc ...

  2. web storage 离线存储

    用来保存键值对数据,数据以属性的方式保存在storage实例对象上   可以用storage1.length来决定键值对的数量,但是无法决定数据的大小,storage1.remainingSpace可 ...

  3. PTA 循环单链表区间删除 (15 分)

    本题要求实现带头结点的循环单链表的创建和单链表的区间删除.L是一个带头结点的循环单链表,函数ListCreate_CL用于创建一个循环单链表,函数ListDelete_CL用于删除取值大于min小于m ...

  4. n! 进制

    n! 进制 Time limit per test: 1.0 seconds Time limit all tests: 1.0 seconds Memory limit: 256 megabytes ...

  5. Problem B: 大整数的加法运算 升级版

    #include <iostream> #include <algorithm> #include <cstdio> #include <cstring> ...

  6. 新增加的HTTP状态码 -- 103

    IETF公布了新的HTTP状态码-103, 总结一下就是提前预加载(css.js)文档,提升用户的访问速度. Summary: a new status code that lets the serv ...

  7. StringBulider与StringBuffer的异同

    相同点:两者的功能都是相同的,没有任何差别. 不同点:StringBulider 不是同步的,也是线程不安全的,当使用多线程处理缓冲区时,不能使用.但是单线程访问的时候效率高,如果是单线程处理缓冲区资 ...

  8. 分页查询时,使用cookie保存上次的查询条件。jQuery实现方法以及中间遇到的坑

    今天做分页查询时需要在跳转页面时保存上次查询的条件,如下: 实现的大致思路就是用cookie本地保存. 其中需要用到jQuery.Cookie插件. 使用方法很简单: 存数据:$.cookie(“ke ...

  9. div内长串数字或字母不断行处理

    比如: <div>1111tryrt645645rt4554111112324353453454364</div> <div>qwewretrytuytuiyiuo ...

  10. C#移位运算(左移和右移)

    C#是用<<(左移) 和 >>(右移) 运算符是用来执行移位运算. 左移 (<<) 将第一个操作数向左移动第二个操作数指定的位数,空出的位置补0.  左移相当于乘. ...