前言
应用切面一段时间,写个根本切面没有问题。
然而这次应用切面时遇到了问题,发现切面没有执行,找谬误又无从找起,只能硬看代码。
大略代码是这样的
public class ImportExcelServiceImpl { public void readFromFileAndSetAnswerSheets() { ... setAnswerSheet(currentRow); ... } @UpdateAnswerSheetTotalNumber public AnswerSheet setAnswerSheet(Row currentRow) { ... return answerSheet; }}
这是被切办法
@Aspect@Componentpublic class UpdateAnswerSheetTotalNumberAspect { @Pointcut("@annotation(....UpdateAnswerSheetTotalNumber)") public void annotationPointCut() { } @AfterReturning(value = "annotationPointCut()", returning = "answerSheet") public void after(AnswerSheet answerSheet) { ... }
这是切面
起因
找了半天找不进去哪里错了,就去问了老师,老师看出了问题所在。
原来我的被切办法是setAnswerSheet()
,调用被切办法是通过this.setAnswerSheet()
调用的,这就是对象内调用。而切面是基于代理模式,对象内调用办法是不走代理的,当然是不起作用的。
原来写的被切办法都是在一个对象中的办法调用另一个对象中的a办法的状况下。
此时spring会为被调用办法所在对象生成一个代理,此代理领有与服务雷同的办法,如果办法没有被执行切面,则在代理中间接将执行的办法转发给理论的服务,如果有切面,则会在代理中实现切面,这就是切面的原理。
咱们在类中打入断点
其中userServiceImpl.frozen使咱们的被切办法。注入的类名总是相似UserServiceImpl$$EnhancerBySpringCGLIB$$1c76af9d
。为了让调用方取得UserServiceImpl
的援用,它必须继承自UserServiceImpl
。而后,该代理类会覆写所有public
和protected
办法,并在外部将调用委托给原始的UserServiceImpl
实例。~~~~
解决
解决的方法就是本人注入本人
class A { @Autowired A a; public void test() { // 这样应用切不到,是对象的外部调用 this->setXxx(); // 这样用就能够,因为注入的a实际上是a的代理 a->setXxx(); } @Xxxxx public xxx setXxx() { }}
而这种依赖注入只能应用@Autowired的模式,不能应用构造函数的模式,构造函数模式会造成依赖注入的死循环。
总结
原来只会用AOP而不懂AOP的原理,认为他就如同@before的作用一样简略,直到遇到问题,能力了解aop的原理。