深刻aop

前言

使用切面一段時間,寫個基本切面沒有問題。
然而此次使用切面時遇到了問題,發現切面沒有執行,找錯誤又無從找起,只能硬看代碼。
大概代碼是這樣的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()調用的,這就是對象內調用。而切面是基於代理模式,對象內調用方法是不走代理的,固然是不起做用的。
image.png
原來寫的被切方法都是在一個對象中的方法調用另外一個對象中的a方法的狀況下。
此時spring會爲被調用方法所在對象生成一個代理,此代理擁有與服務相同的方法,若是方法沒有被執行切面,則在代理中直接將執行的方法轉發給實際的服務,若是有切面,則會在代理中完成切面,這就是切面的原理。
咱們在類中打入斷點
image.png
其中userServiceImpl.frozen使咱們的被切方法。注入的類名老是相似UserServiceImpl$$EnhancerBySpringCGLIB$$1c76af9d。爲了讓調用方得到UserServiceImpl的引用,它必須繼承自UserServiceImpl。而後,該代理類會覆寫全部publicprotected方法,並在內部將調用委託給原始的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

相關文章
相關標籤/搜索