1. 程式人生 > >Android Studio中AspectJ的簡單使用一(自定義PointCut)

Android Studio中AspectJ的簡單使用一(自定義PointCut)

    使用自定義註解的方式,步驟如下

     1.建立自定義註解;

     2.建立操作類(切入檔案);

     3.呼叫註解。

    一、建立自定義註解。

      程式碼如下。

package cm.richeninfo.com.astestaspect20180309.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Created by wangxiaowu on 2018/3/9  14:08
 * decribe
 * 註解類
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BehaviorTrace {
    String value();
}

     注意:

       @Target、@Retention、@interface

     備註:

     java中元註解有四個: @Retention @Target @Document @Inherited;
   @Retention:註解的保留位置         
      @Retention(RetentionPolicy.SOURCE)   //註解僅存在於原始碼中,在class位元組碼檔案中不包含
      @Retention(RetentionPolicy.CLASS)     // 預設的保留策略,註解會在class位元組碼檔案中存在,但執行時無法獲得,
      @Retention(RetentionPolicy.RUNTIME)  // 註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到
  
  @Target:註解的作用目標
        @Target(ElementType.TYPE)   //介面、類、列舉、註解
        @Target(ElementType.FIELD) //欄位、列舉的常量
        @Target(ElementType.METHOD) //方法
        @Target(ElementType.PARAMETER) //方法引數
        @Target(ElementType.CONSTRUCTOR)  //建構函式
        @Target(ElementType.LOCAL_VARIABLE)//區域性變數
        @Target(ElementType.ANNOTATION_TYPE)//註解
        @Target(ElementType.PACKAGE) ///包   
 
     @Document:說明該註解將被包含在javadoc中
 

   @Inherited:說明子類可以繼承父類中的該註解

     RetentionPolicy.SOURCE:註解只保留在原始檔,當Java檔案編譯成class檔案的時候,註解被遺棄;
     RetentionPolicy.CLASS:註解被保留到class檔案,但jvm載入class檔案時候被遺棄,這是預設的生命週期;

     RetentionPolicy.RUNTIME:註解不僅被儲存到class檔案中,jvm載入class檔案之後,仍然存在;

二、建立操作類

        程式碼如下。

package cm.richeninfo.com.astestaspect20180309.aspect;

import android.util.Log;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.RequiredTypes;
import org.aspectj.lang.reflect.MethodSignature;

import java.util.Objects;

import cm.richeninfo.com.astestaspect20180309.annotation.BehaviorTrace;

/**
 * Created by wangxiaowu on 2018/3/9  14:36
 * decribe
 */
@Aspect
public class BehaviorTraceAspect {

    //關聯的註解類cm.richeninfo.com.astestaspect20180309.annotation.BehaviorTrace
    @Pointcut("execution(@cm.richeninfo.com.astestaspect20180309.annotation.BehaviorTrace * *(..))")
     public void methodAnnotatedWithBehaviorTraceAspect(){
        //下面的程式碼沒有執行
        Log.d("system.out","methodAnnotated**********************");
    }

//    @Before("methodAnnotatedWithBehaviorTraceAspect()")
//    public void beforeMethod() throws Throwable{
//        Log.v("system.out","before method is executed");
//    }
//
//    @After("methodAnnotatedWithBehaviorTraceAspect()")
//    public void afterMethod() throws Throwable{
//        Log.v("system.out","after method is executed");
//    }

    //關聯的操作methodAnnotatedWithBehaviorTraceAspect()
    @Around("methodAnnotatedWithBehaviorTraceAspect()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
        Object result=null;
        if(null!=joinPoint){
            MethodSignature methodSignature=(MethodSignature)joinPoint.getSignature();
            String className=methodSignature.getDeclaringType().getSimpleName();
            String methodName=methodSignature.getName();
            String funName=methodSignature.getMethod().getAnnotation(BehaviorTrace.class).value();
            Log.d("system.out","arround method is executed.before");

            //統計時間
            long begin=System.currentTimeMillis();
            result=joinPoint.proceed();
            long duration=System.currentTimeMillis()-begin;
            Log.d("system.out",String.format("around method is executed .after 功能:%s,%s類的%s方法執行了,用時%d ms",funName,className,methodName,duration));
            return result;
        }
        return result;
    }
}

     注意:

      類必須要加上@Aspect註解。再宣告一個方法作為切點,這個方法需要加上註解: 

      @pointcut(execution(@全類名 * *(. .)))        後面的兩個表示*匹配所有的方法名,兩個.表示匹配所有的方法引數

    備註:

      AspectJ的切入點表示式中,可以用execution、call。

      對於Call來說:

      Call(Before)      Pointcut{            Pointcut Method     }    Call(After)    對於Execution來說:    Pointcut{        execution(Before)        Pointcut Method        execution(After)    }

三、呼叫註解

程式碼如下。

package cm.richeninfo.com.astestaspect20180309;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import cm.richeninfo.com.astestaspect20180309.annotation.BehaviorTrace;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        findViewById(R.id.activity_main_tv1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                testAspect();
            }
        });
    }

    @BehaviorTrace("測試 aspect")
    private int testAspect(){
        Log.v("system.out","testAspect inner is executed");

        return 100;
    }
}