【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行 ( 定义连接点注解 | 定义 Aspect 切面 | 定义切入点 | 逐个处理切入点的各个连接点 )
文章目錄
- 一、定義 Join Point 連接點注解
- 二、定義 Aspect 切面
- 1、定義 Aspect 切面
- 2、定義 Aspect 切面
- 3、逐個處理切入點的各個連接點
- 4、完整 Aspect 切面代碼
- 三、使用 AspectJ 埋點并監(jiān)控方法性能
一、定義 Join Point 連接點注解
要監(jiān)控哪些方法 , 首先要對該方法添加注解 , 該注解標(biāo)記哪些方法是 Join Point 連接點 , 所有被該注解標(biāo)記的方法構(gòu)成 一組 Join Point 連接點 , 即 Point Cut 切入點 ;
package com.example.aop_demo;import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/*** 該注解標(biāo)記哪些方法是 Join Point 連接點* 所有被該注解標(biāo)記的方法構(gòu)成 一組 Join Point 連接點 , 即 Point Cut 切入點*/ @Retention(RetentionPolicy.RUNTIME) // 注解保留到運行時 @Target(ElementType.METHOD) // 注解作用于方法上 public @interface Monitor {String value(); }注解的用法如下 : 如果想要監(jiān)控下面的 public void textClick(View view) 方法 , 在該方法上添加 @Monitor 注解即可 ;
@Monitor("textClick")public void textClick(View view) {// 休眠 500 msSystemClock.sleep(500);}二、定義 Aspect 切面
1、定義 Aspect 切面
Aspect 切面 : Java 中的類聲明是 對事物的抽象 , AspectJ 中的 Aspect 切面就是 對切面的抽象 , 其中包含了 Point Cut 切入點 和 Advice 通知 ; 使用 @Aspect 注解修飾 ;
/*** 定義 Aspect 切面*/ @Aspect public class MonitorAspect { }2、定義 Aspect 切面
Point Cut 切入點 : 一組 Join Point 連接點 , 通過 邏輯關(guān)系 / 正則表達式 / 通配符 等關(guān)系組合 , 定義了 Advice 通知發(fā)生的位置 ;
解析 "execution(@com.example.aop_demo.Monitor * *(..))" 匹配規(guī)則 :
- @com.example.aop_demo.Monitor 表示帶該注解的方法
- 第 1 個 * 表示在所有包下面
- 第 2 個 * 表示在所有類下面
- (..) 表示所有方法 , 參數(shù)不限
整體含義 : 所有的包 所有的類 中 , 帶有 @com.example.aop_demo.Monitor 注解的方法 , 都是 Pointcut 切入點 , 每個方法都是一個 JoinPoint 連接點 ;
/*** 定義切入點* "execution(@com.example.aop_demo.Monitor * *(..))" 表示* 帶有 @com.example.aop_demo.Monitor 注解的* 所有包下面的 所有類中的 所有方法, 方法參數(shù)不限* 上述方法組成 切入點 , 每個方法都是一個 Join Point 連接點** execution(@com.example.aop_demo.Monitor * *(..)) 解讀* - @com.example.aop_demo.Monitor 表示帶該注解的方法* - 第 1 個 * 表示在所有包下面* - 第 2 個 * 表示在所有類下面* - (..) 表示所有方法 , 參數(shù)不限** 所有的包 所有的類 中 , 帶有 @com.example.aop_demo.Monitor 注解的方法 , 都是 Pointcut 切入點* 上述每個方法都是一個 Join Point 連接點*/@Pointcut("execution(@com.example.aop_demo.Monitor * *(..))")public void pointCut(){}
3、逐個處理切入點的各個連接點
@Around("pointCut()") 注解中傳入的注解屬性是 切入點 的名稱 , 就是上面定義的 public void pointCut(){} 方法對應(yīng)的 Pointcut 切入點 ;
獲取 JoinPoint 連接點 對應(yīng) 方法的相關(guān)屬性 :
- 獲取方法上的注解 , 以及注解屬性 : 首先獲取方法簽名 , 在回去方法簽名對應(yīng)的 Method 對象 , 獲取該對象上的注解 , 根據(jù)注解調(diào)用注解中定義的獲取屬性的接口方法 ;
- 獲取方法名稱 : signature.getDeclaringType() 就是方法所在的類的字節(jié)碼類對象 , 然后調(diào)用 getSimpleName 方法即可獲取類名 ;
- 獲取方法所在類名稱 : 直接調(diào)用方法簽名的 getName 方法 , 即可獲取方法名 ;
調(diào)用 joinPoint.proceed() 方法 , 可同步執(zhí)行該具體的方法 , 方法的上下可以進行用戶自己的埋點業(yè)務(wù)邏輯 , 如統(tǒng)計方法執(zhí)行耗時等操作 ;
// 執(zhí)行具體的方法result = joinPoint.proceed();代碼示例 :
/*** 逐個處理 Pointcut 切入點 中的 JoinPoint 連接點* 一個一個處理** @Around("pointCut()") 注解中傳入的注解屬性是* 切入點的名稱 , 就是上面定義的 public void pointCut(){} 方法** @param joinPoint* @return*/@Around("pointCut()")public Object processJoinPoint(ProceedingJoinPoint joinPoint) {Object result = null;try {// 獲取方法上 @Monitor("onClick") 注解中的注解屬性 字符串// 獲取被 @Monitor("onClick") 注解修飾的方法的 方法簽名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 根據(jù)方法簽名獲取方法// 然后獲取方法上的 @Monitor 注解Monitor annotation = signature.getMethod().getAnnotation(Monitor.class);// 獲取 @Monitor("onClick") 注解中的注解屬性String value = annotation.value();// 獲取方法名稱String className = signature.getDeclaringType().getSimpleName();// 獲取方法所在的類名String methodName = signature.getName();// 記錄方法執(zhí)行開始時間long startTime = System.currentTimeMillis();// 執(zhí)行具體的方法result = joinPoint.proceed();// 記錄方法執(zhí)行結(jié)束時間long endTime = System.currentTimeMillis();Log.i(TAG, "執(zhí)行 " + className + " 中的 " + methodName +" 方法花費了 " + (endTime - startTime) + " ms , 注解屬性為 " + value );} catch (Throwable throwable) {throwable.printStackTrace();}return result;}4、完整 Aspect 切面代碼
package com.example.aop_demo;import android.util.Log;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature;/*** 定義 Aspect 切面*/ @Aspect public class MonitorAspect {private static final String TAG = "MonitorAspect";/*** 定義切入點* "execution(@com.example.aop_demo.Monitor * *(..))" 表示* 帶有 @com.example.aop_demo.Monitor 注解的* 所有包下面的 所有類中的 所有方法, 方法參數(shù)不限* 上述方法組成 切入點 , 每個方法都是一個 Join Point 連接點** execution(@com.example.aop_demo.Monitor * *(..)) 解讀* - @com.example.aop_demo.Monitor 表示帶該注解的方法* - 第 1 個 * 表示在所有包下面* - 第 2 個 * 表示在所有類下面* - (..) 表示所有方法 , 參數(shù)不限** 所有的包 所有的類 中 , 帶有 @com.example.aop_demo.Monitor 注解的方法 , 都是 Pointcut 切入點* 上述每個方法都是一個 Join Point 連接點*/@Pointcut("execution(@com.example.aop_demo.Monitor * *(..))")public void pointCut(){}/*** 逐個處理 Pointcut 切入點 中的 JoinPoint 連接點* 一個一個處理** @Around("pointCut()") 注解中傳入的注解屬性是* 切入點的名稱 , 就是上面定義的 public void pointCut(){} 方法** @param joinPoint* @return*/@Around("pointCut()")public Object processJoinPoint(ProceedingJoinPoint joinPoint) {Object result = null;try {// 獲取方法上 @Monitor("onClick") 注解中的注解屬性 字符串// 獲取被 @Monitor("onClick") 注解修飾的方法的 方法簽名MethodSignature signature = (MethodSignature) joinPoint.getSignature();// 根據(jù)方法簽名獲取方法// 然后獲取方法上的 @Monitor 注解Monitor annotation = signature.getMethod().getAnnotation(Monitor.class);// 獲取 @Monitor("onClick") 注解中的注解屬性String value = annotation.value();// 獲取方法名稱String className = signature.getDeclaringType().getSimpleName();// 獲取方法所在的類名String methodName = signature.getName();// 記錄方法執(zhí)行開始時間long startTime = System.currentTimeMillis();// 執(zhí)行具體的方法result = joinPoint.proceed();// 記錄方法執(zhí)行結(jié)束時間long endTime = System.currentTimeMillis();Log.i(TAG, "執(zhí)行 " + className + " 中的 " + methodName +" 方法花費了 " + (endTime - startTime) + " ms , 注解屬性為 " + value );} catch (Throwable throwable) {throwable.printStackTrace();}return result;} }
三、使用 AspectJ 埋點并監(jiān)控方法性能
監(jiān)控 public void textClick(View view) 方法性能 , 在該方法上使用 @Monitor 注解 , 該注解已經(jīng)被定義為切入點 , 所有的包 所有的類 中 , 帶有 @com.example.aop_demo.Monitor 注解的方法 , 都是 Pointcut 切入點 , 應(yīng)用執(zhí)行時 , 會自動執(zhí)行埋點業(yè)務(wù)邏輯 , 這里是在方法執(zhí)行前后 , 分別記錄時間 , 最終計算出方法的耗時 ;
package com.example.aop_demo;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle; import android.os.SystemClock; import android.view.View;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Monitor("textClick")public void textClick(View view) {// 休眠 500 msSystemClock.sleep(500);} }執(zhí)行結(jié)果 : 點擊按鈕 , 觸發(fā) textClick 方法 , 觸發(fā)了埋點邏輯 , 自動計算出了該方法的執(zhí)行耗時 ;
2021-09-22 22:23:04.954 12492-12492/com.example.aop_demo I/MonitorAspect: 執(zhí)行 MainActivity 中的 textClick 方法花費了 501 ms , 注解屬性為 textClick總結(jié)
以上是生活随笔為你收集整理的【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行 ( 定义连接点注解 | 定义 Aspect 切面 | 定义切入点 | 逐个处理切入点的各个连接点 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【AOP 面向切面编程】Android
- 下一篇: 【AOP 面向切面编程】Android