成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

嚴重!Spring AOP Bug導致切面重復執行

開發 前端
在Spring中@Aspect定義的切面最終都會轉換為Advisor對象,當代理類在執行時會遍歷所有符合添加的Advisor然后從中取出對應的Advice(MethodInterceptor)對象。

環境:Spring6.1.7

1. 問題復現

為了提高代碼的復用性和維護性,我們設計了一個通用的抽象的切面父類。這個父類封裝了通用的切面邏輯,如日志記錄、性能監控、異常處理等。通過繼承這個抽象父類,具體的業務切面可以輕松地擴展或定制這些通用功能,而無需從零開始編寫切面邏輯。如下示例:

public abstract class CommonAspect {
  @Pointcut("execution(public * com.pack..*.*(..))")
  private void commonPointcut() {}
  @Before("bean(*Service)")
  protected void beforeLog(JoinPoint jp) {
    System.out.println("通用日志記錄...") ;
  }
  @Around("@annotation(monitor)")
  protected Object monitorRun(ProceedingJoinPoint pjp, Monitor monitor) throws Throwable {
    Object ret = null ;
    // TODO
    ret = pjp.proceed() ;
    // TODO
    return ret ;
  }
  // other
}

具體切面子類

@Component
@Aspect
public class LogAspect extends CommonAspect {
  @Override
  public void beforeLog(JoinPoint jp) {
    System.out.println("重寫日志記錄功能") ;
  }
}

當項目運行時出現詭異的問題,既然打印了2次日志信息。

// 測試代碼
AnnotationConfigApplicationContext context = ... ;
PersonService ps = context.getBean(PersonService.class) ;
ps.queryById(1L) ;

執行結果

重寫日志記錄功能
重寫日志記錄功能
查詢Person對象

雖然執行了我們重寫的方法,但是日志確輸出了2遍。

通過debug分析

容器在啟動初始化解析@Aspect切面時,在獲取切面類中的所有方法時,會得到兩個方法(父類及子類重寫的)

圖片圖片

在這里的getAdvisorMethods方法返回了3個方法,其中2個是父類中的一個是子類重寫的方法

圖片圖片

那么接下來根據這2個方法就會生成對應的Advisor對象。

圖片圖片

這也就是為什么重復的原因了。Spring并沒有判斷我當前的這個通知是否是重寫父類的方法。

注:在Spring中@Aspect定義的切面最終都會轉換為Advisor對象,當代理類在執行時會遍歷所有符合添加的Advisor然后從中取出對應的Advice(MethodInterceptor)對象。

既然知道了問題出現的原因,接下來就進行解決該問題。

2. 解決問題

2.1 解決辦法1

我們可以在子類重寫的方法上再加上通知類型,將切入點設置的不匹配任何方法即可

@Before("execution(public * xxxooo())")
@Override
public void beforeLog(JoinPoint jp) {
  System.out.println("重寫日志記錄功能") ;
}

在這里重寫的方法上,將切入點重新寫,該切入點不會匹配任何的方法,這樣修改以后再次執行

重寫日志記錄功能
查詢Person對象

正常執行,沒有重復輸出日志。

2.2 解決辦法2

該方法需要將Spring版本升級到6.1.8,在該版本中解決了該問題。來看看在該版本中是如何解決的。

6.1.8版本

核心方法還是在上面debug是看到的getAdvisors方法中

public class ReflectiveAspectJAdvisorFactory {
  public List<Advisor> getAdvisors(...) {
    List<Advisor> advisors = new ArrayList<>();
    for (Method method : getAdvisorMethods(aspectClass)) {
      // 在這里加入了判斷(當前方法是否與當前切面中的方法相同)
      // 當遍歷到這里的Method是父類中的方法時,這里的getMostSpecificMethod
      // 方法就會判斷根據方法的名稱再從當前切面類中獲取方法(那當然就不同了)
      if (method.equals(ClassUtils.getMostSpecificMethod(method, aspectClass))) {
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
        if (advisor != null) {
          advisors.add(advisor);
        }
      }
    }
  }
}

圖片圖片

在6.1.8版本中通過這種方式就排除了父類的方法。

其它版本

圖片圖片

低于6.1.8版本,都沒有相應的判斷。

責任編輯:武曉燕 來源: Spring全家桶實戰案例源碼
相關推薦

2012-02-10 10:32:33

JavaSpring

2024-04-10 08:59:39

SpringAOP業務

2014-03-24 11:07:18

金山毒霸BUG驅動故障

2009-08-24 09:46:40

面向切面編程AOP

2022-04-22 15:03:14

Android漏洞網絡攻擊

2022-02-16 13:46:40

Spring Aop代碼注解

2013-09-17 10:37:03

AOPAOP教程理解AOP

2024-10-12 14:36:34

2011-04-26 09:33:04

SpringAOP

2023-11-07 16:00:25

面向切面編程開發

2024-05-21 09:55:43

AspectOrientedAOP

2010-06-11 17:08:05

2023-09-04 08:36:19

SpringAop日志輸出

2021-09-27 10:15:10

故障業務方電腦

2009-05-27 09:32:20

2025-04-28 09:15:56

2013-10-21 09:45:23

Windows 8.1Windows 8Windows RT

2022-12-25 16:21:59

iOS蘋果bug

2022-12-19 15:30:23

iOS蘋果功能

2020-10-16 09:40:18

順序Spring AOPHTTP
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩视频专区 | 日韩欧美黄色 | 精品亚洲一区二区三区四区五区 | 国产精品久久久久久久久久久久 | 精品影院 | 精品一二三 | 日韩成人免费视频 | 天天干.com| 澳门永久av免费网站 | 久久久久久免费免费 | 黄色在线 | 欧美aaaaaa| 日韩伦理一区二区 | 国产综合视频 | 国产视频导航 | av一区二区三区 | 日韩黄色av | 日韩欧美视频免费在线观看 | 久久av影院 | 欧美国产精品 | 在线观看国产视频 | 热久久性| 黄 色 毛片免费 | 日韩欧美一区二区三区四区 | 91观看| 亚洲欧美在线观看 | 欧美视频免费在线 | 国产一二区视频 | 国产成人av电影 | 国产精品国产三级国产aⅴ无密码 | 欧美福利精品 | 奇米久久 | 91精品国产一区二区三区香蕉 | 国产高清亚洲 | 亚洲久草 | 国产欧美久久一区二区三区 | 日韩国产专区 | 中文字幕一区二区不卡 | 天堂在线91 | 欧美一级黑人aaaaaaa做受 | 夜夜骚|