日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

環境:Spring5.3.23

1. 介紹

今天看Spring文檔看到這么一個知識點《Control Flow Pointcuts》都不好翻譯

官方原文:

Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, although less powerful. (There is currently no way to specify that a pointcut runs below a join point matched by another pointcut.) A control flow pointcut matches the current call stack. For example, it might fire if the join point was invoked by a method in the com.mycompany.web package or by the SomeCaller class. Control flow pointcuts are specified by using the org.springframework.aop.support.ControlFlowPointcut class.

大意:Spring控制流切入點在概念上類似于aspectj cflow切入點,盡管功能不那么強大。(目前還沒有辦法指定一個切入點在與另一個切入點匹配的連接點下面運行。)控制流切入點與當前調用堆棧匹配。例如,如果連接點由com.mycompany.web包中的方法或someecaller類調用,則可能會觸發該連接點。控制流切入點是通過使用org.springframework.aop.support.ControlFlowPointcut類指定的。

其實看完這個,可能你還是不懂什么意思,接下來我們來跑一個實例,就能明白撒意思了。

2. Control Flow實例

準備幾個方法嵌套調用的類

static class PersonDAO {
  public void save(String name) {
    System.out.println("PersonDAO save method invoke...") ;
  }
}
static class PersonService {
  private PersonDAO dao ;
  public PersonService(PersonDAO dao) {
    this.dao = dao ;
  }
  public void save(String name) {
    System.out.println("PersonService save method inovke...") ;
    this.dao.save(name) ;
  }
}


static class PersonManager {
  private PersonService ps ;
  public void setPs(PersonService ps) {
    this.ps = ps ;
  }
  public void index(String name) {
    System.out.println("PersonManager index method invoke...") ;
    this.ps.save(name) ;
  }
}

上面的類及方法調用非常簡單:PersonManager ---> PersonService ---> PersonDAO。接下來是通過編程的方式創建PersonService代理對象。

// 實例化上面的類
PersonDAO dao = new PersonDAO() ;
PersonService target = new PersonService(dao) ;


PersonManager pm = new PersonManager() ;


Class<?> clazz = PersonManager.class ;
String methodName = "index" ;
// 定義切入點
ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName) ;
// 定義通知
MethodInterceptor logInterceptor = invocation -> {
  System.out.println("before log...") ;
  Object ret = invocation.proceed() ;
  System.out.println("after log...") ;
  return ret ;
} ;
// 定義切面


DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(pointcut, logInterceptor) ;
// 通過ProxyFactory創建代理對象,創建的是PersonService對象的代理
ProxyFactory factory = new ProxyFactory(target) ;
factory.addAdvisor(advisor) ;
// 基于CGLIB生成代理
factory.setProxyTargetClass(true) ;
PersonService ps = (PersonService) factory.getProxy() ;


pm.setPs(ps) ;


pm.index("張三") ;

控制臺輸出

PersonManager index method invoke...
before log...
PersonService save method inovke...
PersonDAO save method invoke...
after log...

從輸出的結果發現,在PersonService#save方法之前之前和之后分別打印了日志信息。原理是什么呢?這里我們需要先看ControlFlowPointcut 切入點是如何工作的。

ControlFlowPointcut核心方法

這里只列出了幾個重要的方法,在spring中只支持方法級別的攔截。

public class ControlFlowPointcut implements Pointcut, ClassFilter, MethodMatcher, Serializable {
  private final Class<?> clazz;
  @Nullable
  private final String methodName;
  // 對應類級別的匹配全部返回true,就是都匹配
  @Override
  public boolean matches(Class<?> clazz) {
    return true;
  }
  // 方法匹配,直接true
  @Override
  public boolean matches(Method method, Class<?> targetClass) {
    return true;
  }
  // 這里是關鍵,只有isRuntime返回了true才有可能調用下面3個參數的matches方法
  @Override
  public boolean isRuntime() {
    return true;
  }
  // 該方法的調用需要上面2個參數的matches方法返回true且isRuntime方法也返回true才會調用這里
  @Override
  public boolean matches(Method method, Class<?> targetClass, Object... args) {
    // 遍歷當前線程的執行棧情況(也就是當前方法的調用棧情況)
    for (StackTraceElement element : new Throwable().getStackTrace()) {
      // 這里就開始判斷當前執行的類是否與給定的類相同 && 當前設置的methodName為空或者當前棧執行的方法名與給定的方法名相同
      if (element.getClassName().equals(this.clazz.getName()) &&
          (this.methodName == null || element.getMethodName().equals(this.methodName))) {
        // 最終這里只有返回了true,我們上面的通知MethodInterceptor才會被執行
        return true;
      }
    }
    return false;
  }
}

有了上面源碼的分析后,我們再來看看上面的示例代碼:

// 指明要匹配的類
Class<?> clazz = PersonManager.class ;
// 指明要匹配的方法名
String methodName = "index" ;
/** 
 * 將傳入到切入點中;而在該切入點的matches方法中進行了判斷,
 * 整個執行的線程棧中的所有類及方法是否與這里給定的相同,
 * 只有相同了攔截器才能執行
 */
ControlFlowPointcut pointcut = new ControlFlowPointcut(clazz, methodName) ;

分析到這你應該知道這個Control Flow有撒用了吧,總結:

Control Flow就是用來判斷當前執行的線程棧中(所有方法的調用)是否與你給定的類及方法匹配,只有匹配了才能執行我們的增強(通知)代碼。

簡單說:我PersonService想監控PersonManager中的index方法是否調用了我。

官方有這段說明:

Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account method arguments as well as static information. This means that they must be evaluated with every method invocation and that the result cannot be cached, as arguments will vary.

The mAIn example is the control flow pointcut.

大意:與靜態快捷方式相比,動態快捷方式的評估成本更高。它們會考慮方法參數和靜態信息。這意味著每次調用方法時都必須對其進行評估,而且由于參數會發生變化,因此無法緩存評估結果。控制流快捷方式就是一個主要的例子。

3. Control Flow性能

同樣來自官方說明:

Control flow pointcuts are significantly more expensive to evaluate at runtime than even other dynamic pointcuts. In JAVA 1.4, the cost is about five times that of other dynamic pointcuts.

大意:與其他動態切入點相比,控制流切入點在運行時評估的成本要高得多。在Java1.4中,成本大約是其他動態切入點的五倍。

分享到:
標簽:Spring
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定