在使用AOP切面时,明明没有错,却总是不执行

2022-06-28 13:16:18

前言

使用切面一段时间,写个基本切面没有问题。
然而这次使用切面时遇到了问题,发现切面没有执行,找错误又无从找起,只能硬看代码。
大概代码是这样的

publicclassImportExcelServiceImpl{publicvoidreadFromFileAndSetAnswerSheets(){...setAnswerSheet(currentRow);...}@UpdateAnswerSheetTotalNumberpublic AnswerSheetsetAnswerSheet(Row currentRow){...return answerSheet;}}

这是被切方法

@Aspect@ComponentpublicclassUpdateAnswerSheetTotalNumberAspect{@Pointcut("@annotation(....UpdateAnswerSheetTotalNumber)")publicvoidannotationPointCut(){}@AfterReturning(value="annotationPointCut()", returning="answerSheet")publicvoidafter(AnswerSheet answerSheet){...}

这是切面

原因

找了半天找不出来哪里错了,就去问了老师,老师看出了问题所在。
原来我的被切方法是setAnswerSheet(),调用被切方法是通过this.setAnswerSheet()调用的,这就是对象内调用。而切面是基于代理模式,对象内调用方法是不走代理的,当然是不起作用的。
在这里插入图片描述

原来写的被切方法都是在一个对象中的方法调用另一个对象中的a方法的情况下。
此时spring会为被调用方法所在对象生成一个代理,此代理拥有与服务相同的方法,如果方法没有被执行切面,则在代理中直接将执行的方法转发给实际的服务,如果有切面,则会在代理中完成切面,这就是切面的原理。
我们在类中打入断点在这里插入图片描述
其中userServiceImpl.frozen使我们的被切方法。注入的类名总是类似UserServiceImpl E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIBEnhancerBySpringCGLIB1c76af9d。为了让调用方获得UserServiceImpl的引用,它必须继承自UserServiceImpl。然后,该代理类会覆写所有public和protected方法,并在内部将调用委托给原始的UserServiceImpl实例。~~~~

解决

解决的办法就是自己注入自己

classA{@Autowired
  A a;publicvoidtest(){// 这样使用切不到,是对象的内部调用this->setXxx();// 这样用就可以,因为注入的a实际上是a的代理
    a->setXxx();}@Xxxxxpublic xxxsetXxx(){}}

而这种依赖注入只能使用@Autowired的形式,不能使用构造函数的形式,构造函数形式会造成依赖注入的死循环。

总结

原来只会用AOP而不懂AOP的原理,以为他就如同@before的作用一样简单,直到遇到问题,才能理解aop的原理。

参考:《2020最新Java基础精讲视频教程和学习路线!》
原文链接:https://segmentfault.com/a/1190000039297484

  • 作者:didiao java
  • 原文链接:https://blog.csdn.net/weixin_46699878/article/details/114318993
    更新时间:2022-06-28 13:16:18