AspectJ學習筆記

洛小白發表於2019-04-01
  1. 介紹

    1. AspectJ是一個基於Java語言的AOP框架
    2. Spring2.0以後新增了對AspectJ切點表達支援
    3. @AspectJ是AspectJ1.5新增功能,通過JDK5註解技術,允許Bean類中定義切面,新版本Spring框架,建議使用AspectJ方式來開發AOP
    4. 主要用途:自定義開發
  2. 切入點表示式

    1. execution() 用於描述方法

      <!--建立目標類-->
      <bean id="userService" class="com.adolph.AOP.jdk.UserServiceImpl"></bean>
      
      <!--建立切面類-->
      <bean id="myAspect" class="com.adolph.AOP.jdk.MyAspect"></bean>
      
      <!--aop程式設計
          使用<aop:config>進行配置
          proxy-target-class="true":使用cglib代理
           <aop:pointcut>切入點,從目標物件獲得具體方法
           <aop:advisor> 特殊的切面,只有一個通知和一個切入點
              advice-ref:通知引用
              pointcut-ref:切入點引用
            切入點表示式:
              execution(* com.adolph.AOP.jdk.*.*(..))
              選擇方法 返回值任意  包 類名任意 方法名任意 引數任意
      -->
      <aop:config proxy-target-class="true">
          <aop:pointcut id="myPointCut" expression="execution(* com.adolph.AOP.jdk.*.*(..))"/>
          <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
      </aop:config>
      複製程式碼
      1. 語法:execution(修飾符 返回值 包.類.方法(引數) throws 異常)

        1. 修飾符:一般省略
        2. 返回值:*(任意)
          1. 省略
            1. con.adolph.cn 固定包
            2. com.adolph. adolph包下面子包任意*
            3. com.adolph.. adolph包下面的所有子包(含自己)
          1. 省略
          2. UserServiceImpl 指定類
          3. *Impl 以Impl結尾
          4. User 以User開頭*
          5. *. 任意
        3. 方法名
          1. 不能省略
          2. addUser 固定方法
          3. add 以add開頭*
          4. *Do 以Do結尾
          5. *. 任意
        4. 引數
          1. () 無參
          2. (int) 一個整型
          3. (int,int) 兩個
          4. (..) 引數任意
        5. throws
          1. 可省略,一般不寫
      2. 綜合

           `execution(* com.adolph.AOP.jdk.*.*(..))`
        複製程式碼
  3. AspectJ通知型別

    1. aop聯盟定義通知型別,具有特性介面,必須實現,從而確定方法名稱
    2. aspectj 通知型別,只定義型別名稱。以及方法格式
    3. 個數:6種,知道5種,掌握一種
      1. before:前置通知
      2. afterReturning:後置通知(應用:常規資料處理)
      3. around:環繞通知(應用:十分強大,可以做任何事情)
        1. 方法執行前後分別執行、可以阻止方法的執行
        2. 必須手動執行目標方法
      4. afterThrowing:丟擲異常通知(應用:包裝異常資訊)
      5. after:最終通知(應用:清理現場)
  4. 基於XML

    1. 目標類:介面+實現

    2. 切面類:編寫多個通知,採用aspectJ通知名稱任意(方法名任意)

    3. aop程式設計:將通知應用到目標類

    4. 測試

    5. 目標類

      public class UserServiceImpl {
          public void addUser() {
              System.out.println("addUser");
          }
      
          public void updateUser() {
              System.out.println("updateUser");
          }
      
          public void deleteUser() {
              System.out.println("deleteUser");
          }
      }
      複製程式碼
    6. 切面類

      /**
       * 切面類,含有多個通知
       */
      public class MyAspect {
      
          public void myBefore(JoinPoint joinPoint) {
              System.out.println("前置通知" + joinPoint.getSignature().getName()); //獲得目標方法名
          }
      
          public void myAfterReturning(JoinPoint joinPoint, Object ret) {
              System.out.println("後置通知" + joinPoint.getSignature().getName() + "____" + ret); //獲得目標方法名
          }
      
          public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
              System.out.println("前");
              //手動執行目標方法
              Object proceed = joinPoint.proceed();
              System.out.println("後");
              return proceed;
          }
      
          public void MyAfterThrowing(JoinPoint joinPoint,Throwable e){
              System.out.println("丟擲異常通知:");
          }
      
          public void after(JoinPoint joinPoint){
              System.out.println("最終");
          }
      }
      複製程式碼
    7. xml

      <!--建立目標類-->
      <bean id="userService" class="com.adolph.AOP.jdk.UserServiceImpl"></bean>
      
      <!--建立切面類-->
      <bean id="myAspect" class="com.adolph.AOP.jdk.MyAspect"></bean>
      <!--aop程式設計
      -->
      <aop:config>
          <!--將切面類 宣告成切面,從而獲得通知(方法),ref:切面類引用-->
          <aop:aspect ref="myAspect">
              <!--宣告一個切入點,所有的通知都可以使用
                  expression:切入點表示式
                  id:名稱用於其他通知引用
                  -->
              <aop:pointcut id="myPointcut" expression="execution(* com.adolph.AOP.jdk.UserServiceImpl.*(..))"></aop:pointcut>
      
              <!--前置通知
              method:通知,及方法名
              pointcut:切入點表示式,此表示式只能當前通知使用
              pointcut-ref:切入點引用,可以與其他通知點共享切入點
               通知方法格式:public void myBefore(JoinPoint joinPoint)
               引數JoinPoint 用於描述連線點(目標方法),獲得目標方法名稱等
              -->
              <aop:before method="myBefore" pointcut-ref="myPointcut"></aop:before>
      
              <!--後置通知,目標方法執行,獲得返回值
              public void myAfterReturning(JoinPoint joinPoint,Object ret)
              引數1:連線點描述
              引數2:型別Object,引數名returning配置的
              -->
              <aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut" returning="ret"></aop:after-returning>
      
              <!--環繞通知
                public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable
                返回值:Object
                方法名:任意
                引數:Proceeding JoinPoint
                丟擲異常
              -->
              <aop:around method="myAround" pointcut-ref="myPointcut"></aop:around>
      
      
              <!--異常通知
              throwing:通知方法的第二個引數名稱
              -->
              <aop:after-throwing method="MyAfterThrowing" pointcut-ref="myPointcut" throwing="e"></aop:after-throwing>
      
              <!--最終通知-->
              <aop:after method="after" pointcut-ref="myPointcut"></aop:after>
          </aop:aspect>
      </aop:config>
      複製程式碼
  5. 基於註解

    1. 替換bean

      
      <!--掃描-->
      <context:component-scan base-package="com.adolph.AOP"></context:component-scan>
      複製程式碼
      @Component
      public class MyAspect
      複製程式碼
    2. 必須進行aspectj自動代理

      <!--確定aop註解生效-->
      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
      複製程式碼
    3. 宣告切面

      @Component
      @Aspect
      public class MyAspect
      複製程式碼
    4. 設定前置通知

         @Before("execution(* com.adolph.AOP.jdk.UserServiceImpl.*(..))")
          public void myBefore(JoinPoint joinPoint) {
              System.out.println("前置通知" + joinPoint.getSignature().getName()); //獲得目標方法名
          }
      複製程式碼
    5. 替換公共切入點

      @Pointcut("execution(* com.adolph.AOP.jdk.UserServiceImpl.*(..))")
      private void myPointCut(){
      
      }
      複製程式碼
    6. 設定後置通知

      @AfterReturning(value = "myPointCut()",returning = "ret")
      public void myAfterReturning(JoinPoint joinPoint, Object ret) {
          System.out.println("後置通知" + joinPoint.getSignature().getName() + "____" + ret); //獲得目標方法名
      }
      複製程式碼
    7. 設定環繞通知

      @Around(value = "myPointCut()")
      public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
          System.out.println("前");
          //手動執行目標方法
          Object proceed = joinPoint.proceed();
          System.out.println("後");
          return proceed;
      }
      複製程式碼
    8. 設定丟擲異常

      @AfterThrowing(value = "myPointCut()",throwing = "e")
      public void MyAfterThrowing(JoinPoint joinPoint,Throwable e){
          System.out.println("丟擲異常通知:");
      }
      複製程式碼
    9. 最終通知

      @AfterThrowing(value = "myPointCut()",throwing = "e")
      public void MyAfterThrowing(JoinPoint joinPoint,Throwable e){
          System.out.println("丟擲異常通知:");
      }
      複製程式碼