点击上方蓝色“方志朋”,选择“设为星标”

回复“666”获取独家整理的学习资料!

很多读者看完之后表示用起来很爽,但是后台也有人留言说自己配置了Spring的AOP之后,发现切面不生效。

其实,这个问题我在用的过程中也遇到过,而且还是同一个问题一天之内遇到了两次。

说明这个问题很容易被忽略,并且这个问题带来的后果可能是极其严重的。那么,我们就来简单回顾一下问题是怎么样的。

问题重现

最初我定义了一个注解,希望可以方便统一的对一些数据库操作做缓存。于是就有了以下代码:

首先,定义一个注解:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Cacheable {/*** 策略名称,需要保证唯一* @return*/public String keyName();/*** 超时时长,单位:秒* @return*/public int expireTime();}

然后自定义一个切面,对所有使用了该注解的方法进行切面处理:

@Aspect@Componentpublic class StrategyCacheAspect {private static final Logger LOGGER = LoggerFactory.getLogger(FacadeAspect.class);@Around("@annotation(com.hollis.cache.StrategyCache)")public Object cache(ProceedingJoinPoint pjp) throws Throwable {// 先查缓存,如果缓存中有值,直接返回。如果缓存中没有,先执行方法,再将返回值存储到缓存中。}}

然后就可以使用该注解了,使用方法如下:

@Componentpublic class StrategyService extends BaseStrategyService  {public PricingResponse getFactor(Map<String, String> pricingParams) {// 做一些参数校验,以及异常捕获相关的事情return this.loadFactor(tieredPricingParams);}@Override@StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)private PricingResponse loadFactor(Map<String, String> pricingParams) {//代码执行}}

以上,对loadFactor方法增加了切面,为了方便使用,我们还定义了一个getFactor方法,设置为public,方便外部调用。

但是,在调试过程中,我发现我们设置在loadFactor方法上面的切面并没有成功,无法执行切面类。

于是开始排查问题具体是什么。

问题排查

为了排查这个问题,首先是把所有的代码检查一遍,看看切面的代码是不是有问题,有没有可能有手误打错了字之类的。

但是发现都没有。于是就想办法找找问题。

接下来我把loadFactor的访问权限从private改成public,发现没有效果。

然后我尝试着在方法外直接调用loadFactor而不是getFactor。

发现这样做就可以成功的执行到切面里面了。

发现这一现象的时候,我突然恍然大悟,直捶大腿。原来如此,原来如此,就应该是这样的。

我突然就想到了问题的原因。其实原因挺简单的,也是我之前了解到过的原理,但是在问题刚刚发生的时候我并没有想到这里,而是通过debug,发现这个现象之后我才突然想到这个原理。

那么,就来说说为什么会发生这样的问题。

代理的调用方式

我们发现上面的问题关键在于loadFactor方法被调用的方式不同。我们知道,方法的调用通常有以下几种方式:

1、在类内部,通过this进行自调用:

public class SimplePojo implements Pojo {public void foo() {// this next method invocation is a direct call on the 'this' referencethis.bar();}public void bar() {// some logic...}}

2、在类外部,通过该类的对象进行调用

public class Main {public static void main(String[] args) {Pojo pojo = new SimplePojo();// this is a direct method call on the 'pojo' referencepojo.foo();}}

类关系及调用过程中如下图:

如果是静态方法,也可以通过类直接调用。

3、在类外部,通过该类的代理对象进行调用:

public class Main {public static void main(String[] args) {ProxyFactory factory = new ProxyFactory(new SimplePojo());factory.addInterface(Pojo.class);factory.addAdvice(new RetryAdvice());Pojo pojo = (Pojo) factory.getProxy();// this is a method call on the proxy!pojo.foo();}}

类关系及调用过程中如下图:

那么,Spring的AOP其实是第三种调用方式,就是通过代理对象调用,只有这种调用方式,才能够在真正的对象的执行前后,能够让代理对象也执行相关代码,才能起到切面的作用。

而对于使用this的方式调用,这种只是自调用,并不会使用代理对象进行调用,也就无法执行切面类。

问题解决

那么,我们知道了,想要真正的执行代理,那么就需要通过代理对象进行调用而不是使用this调用的方式。

那么,这个问题的解决办法也就是想办法通过代理对象来调用目标方法即可。

这种问题的解决网上有很多种办法,这里介绍一个相对简单的。其他的更多的办法大家可以在网上找到一些案例。搜索关键词"AOP 自调用"即可。

获取代理对象进行调用

我们需要修改一下前面的StrategyService的代码,修改成以下内容:

@Componentpublic class StrategyService{public PricingResponse getFactor(Map<String, String> pricingParams) {// 做一些参数校验,以及异常捕获相关的事情// 这里不使用this.loadFactor而是使用AopContext.currentProxy()调用,目的是解决AOP代理不支持方法自调用的问题if (AopContext.currentProxy() instanceof StrategyService) {return ((StrategyService)AopContext.currentProxy()).loadFactor(tieredPricingParams);} else {// 部分实现没有被代理过,则直接进行自调用即可return loadFactor(tieredPricingParams);}}@Override@StrategyCache(keyName = "key0001", expireTime = 60 * 60 * 2)private PricingResponse loadFactor(Map<String, String> oricingParams) {//代码执行}}

即使用AopContext.currentProxy()获取到代理对象,然后通过代理对象调用对应的方法。

还有个地方需要注意,以上方式还需要将Aspect的expose-proxy设置成true。如果是配置文件修改:

 <aop:aspectj-autoproxy proxy-target-class="true" expose-proxy="true"/>

如果是SpringBoot,则修改应用启动入口类的注解:

@EnableAspectJAutoProxy(exposeProxy = true)public class Application {}

总结

以上,我们分析并解决了一个Spring AOP不支持方法自调用的问题。

AOP失败这个问题,其实还是很严重的,因为如果发生非预期的失效,那么直接问题就是没有执行切面方法,更严重的后果可能是诸如事务未生效、日志未打印、缓存未查询等各种问题。

所以,还是建议大家看完此文之后,统查一下自己的代码,是否存在方法自调用的情况。这种情况下,任何切面都是无法生效的!

热门内容:
  • 微服务架构:注册中心 ZooKeeper、Eureka、Consul 、Nacos 对比!

  • 图解ElasticSearch 搜索原理

  • 优雅地处理重复请求(并发请求)——附Java实现

  • SpringBoot集成Swagger-Bootstrap-UI,页面更清爽!

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。
明天见(。・ω・。)ノ♡

一个Spring AOP的坑!很多人都犯过!相关推荐

  1. sas 检测到开型代码语句的递归_对于标准答案的递归很多人都看不懂,其实就是一个深度优先的遍历。我写了段伪代码,将递归步骤还原并注释了一下,供大家参考,希望大家有所收获。...

    源自:7-5 Python之递归函数 对于标准答案的递归很多人都看不懂,其实就是一个深度优先的遍历.我写了段伪代码,将递归步骤还原并注释了一下,供大家参考,希望大家有所收获. #if条件不成立的省略 ...

  2. 一个团队(很多人)都存在的共性问题

    这是一个共性问题 如果一个团队(这个团队包括很多人),都存在这个问题,那就不是某一个人的问题,也不完全是BOSS的问题,肯定跟这个团队所处的环境.遇到的困难有很大关系:特别是这个团队已经存在很长时间了 ...

  3. 很多人都想考一个RHCE吧,大家不妨看看我是怎么变成一个RHCE的。

    从CHINAUNIX上看到的文章,很有感慨,一个学计算机的同学的经历,在河南这个地方,很多同学毕业,都不干计算机相关的工作,看看人家的酸甜苦辣吧. http://bbs.chinaunix.net/t ...

  4. 小学老师工资多少一个月_小学老师一个月多少工资呢?揭开真实收入,难怪很多人都去当老师...

    图:网络 文:职场实战经验 导语:近日,笔者看到有小学老师反应,她们的工资应该比中学老师的工资高,因为小学生好奇心最重.求知欲最强,问许多看似不合理但却是成年人不会的问题. 小学老师还直言:想想我们小 ...

  5. 很多人都在埋怨没有遇到好的团队,但好的团队不可能凭空出现,一流的团队不能仅靠团队成员努力,作为Leader,要有可行的规划,并坚定地执行、时势地调整(转)...

    <西游记>中的唐僧团队历经千难万险,终于求得真经,目标明确.分工合理为这支队伍最终走向成功奠定了基础.唐僧从一开始,就为这个团队设定了西天取经的目标,虽然经历各种挫折与磨难,但目标从未动摇 ...

  6. 车仪表台上的装饰_仪表台放这个东西,相当于定时炸弹,很多人都忽略了

    阅读本文前,请您先点击上面的蓝色字体"总李谈车",再点击"关注",这样您就可以继续免费收到文章了.每天都有分享,完全是免费订阅,请放心关注.原创持续更新&quo ...

  7. 现在是不是很多人都不愿意在银行存钱?

    虽然很多朋友口口声声说不会把钱存在银行,但实际上却悄悄地在银行存款,这点可以从存款数据看出来. 据有数据显示,自1979年至2018年这39年间,我国金融机构各项存款余额同比增速从未跌破9%. 虽然最 ...

  8. access 战地1不加入ea_炒牛肉时,想要牛肉嫩滑又不老,只需加入1样东西,很多人都不懂...

    炒牛肉时,想要牛肉嫩滑又不老,只需加入1样东西,很多人都不懂 冬季滋补怎么能少得了牛肉,牛肉中含有非常丰富的营养成分,其中蛋白质的含量尤为丰富还有大量的氨基酸,能够提高身体的抗病能力,特别适合手术后或 ...

  9. 从来不敷面膜的人_女人睡觉前,敷面膜洗还是不洗?很多人都做错了,难怪皮肤总不好...

    敷面膜是众多女孩子在晚上都会进行的一个护肤工作,大家都知道像一些明星几乎是每天都要敷一片面膜的,不过她们是因为长期话大浓妆才比较勤,我们一般工作的女孩子大约一周三次就可以了. 面膜可以让我们的皮肤迅速 ...

最新文章

  1. unigui中弹出对话框原窗体是没有了_最前线 | 微信对话框“搜一搜”功能上线,独辟蹊径的腾讯打着什么算盘?...
  2. Java中使用LUA脚本语言
  3. “蚁人”不再是科幻!MIT最新研究,能把任何材料物体缩小1000倍 | Science
  4. 推荐系统-03-简单基于用户的推荐
  5. linux cpu拓扑查看工具 hwloc 简介
  6. 自学python视频教学-想自学Python,不知道网络上的教学视频有用没有?
  7. ArcGIS 10.2 Calculate Value(Data Management) 工具的使用
  8. vue的mixins属性
  9. 自学Python:截取屏幕画面
  10. Linux设备文件的创建
  11. 如何解决软键盘弹出引起的各种不适
  12. Linux安装tomcat并使用+热部署
  13. 计算机病毒有几个阶段,计算机病毒发展9阶段
  14. 数字图像处理 冈萨雷斯 (第四版) 比特平面分层,图像重建
  15. 字符串算法 金策_OI-Public-Library/国家集训队论文1999-2017 at master · BlackWaters/OI-Public-Library · GitHub...
  16. Qt Designer简介
  17. 概念二 python3 中子类继承父类
  18. 数学模型——数学与人类文明的桥梁
  19. linux压缩到最小命令,Linux压缩打包命令
  20. VUE 对@click的认识

热门文章

  1. 2018-3-5(论文——网络中非结构信息的表示与应用)笔记二 (歧义词,未登录词,禁用词)
  2. 手机网页H5 自适应不同分辨率的屏幕 必学标签meta之viewport
  3. 编程之法----面试和算法心得
  4. (转载)虚幻引擎3--9掌握虚幻技术UnrealScript 预处理器
  5. 为python安装numpy和scipy(federo)
  6. Debian刊行版3晋级到4
  7. c#数据结构———二叉查找树
  8. feign调用走不走网关全局拦截_feign服务端出异常客户端处理的方法
  9. 编程能力差,学不好Python、AI、Java等技术,90%是输在了这点上!
  10. 百度“知识增强的跨模态语义理解技术”获国家技术发明奖