使用切面一段時間,寫個基本切面沒有問題。
然而此次使用切面時遇到了問題,發現切面沒有執行,找錯誤又無從找起,只能硬看代碼。
大概代碼是這樣的spring
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) { ... }
這是切面this
找了半天找不出來哪裏錯了,就去問了老師,老師看出了問題所在。
原來個人被切方法是setAnswerSheet()
,調用被切方法是經過this.setAnswerSheet()
調用的,這就是對象內調用。而切面是基於代理模式,對象內調用方法是不走代理的,固然是不起做用的。
原來寫的被切方法都是在一個對象中的方法調用另外一個對象中的a方法的狀況下。
此時spring會爲被調用方法所在對象生成一個代理,此代理擁有與服務相同的方法,若是方法沒有被執行切面,則在代理中直接將執行的方法轉發給實際的服務,若是有切面,則會在代理中完成切面,這就是切面的原理。
咱們在類中打入斷點
其中userServiceImpl.frozen使咱們的被切方法。注入的類名老是相似UserServiceImpl$$EnhancerBySpringCGLIB$$1c76af9d
。爲了讓調用方得到UserServiceImpl
的引用,它必須繼承自UserServiceImpl
。而後,該代理類會覆寫全部public
和protected
方法,並在內部將調用委託給原始的UserServiceImpl
實例。~~~~spa
解決的辦法就是本身注入本身3d
class A { @Autowired A a; public void test() { // 這樣使用切不到,是對象的內部調用 this->setXxx(); // 這樣用就能夠,由於注入的a其實是a的代理 a->setXxx(); } @Xxxxx public xxx setXxx() { } }
而這種依賴注入只能使用@Autowired的形式,不能使用構造函數的形式,構造函數形式會形成依賴注入的死循環。代理
原來只會用AOP而不懂AOP的原理,覺得他就如同@before的做用同樣簡單,直到遇到問題,才能理解aop的原理。code