共计 1303 个字符,预计需要花费 4 分钟才能阅读完成。
前言
应用切面一段时间,写个根本切面没有问题。
然而这次应用切面时遇到了问题,发现切面没有执行,找谬误又无从找起,只能硬看代码。
大略代码是这样的
public class ImportExcelServiceImpl {public void readFromFileAndSetAnswerSheets() {
...
setAnswerSheet(currentRow);
...
}
@UpdateAnswerSheetTotalNumber
public AnswerSheet setAnswerSheet(Row currentRow) {
...
return answerSheet;
}
}
这是被切办法
@Aspect
@Component
public 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 的原理。
正文完