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 注解的 * 所有包下面的 所有类中的 所有方法, 方法参数不限 * 上述方法组成 切入点 , 每个方法都是一个 Join Point 连接点 * * execution(@com.example.aop_demo.Monitor * *(..)) 解读 * - @com.example.aop_demo.Monitor 表示带该注解的方法 * - 第 1 个 * 表示在所有包下面 * - 第 2 个 * 表示在所有类下面 * - (..) 表示所有方法 , 参数不限 * * 所有的包 所有的类 中 , 带有 @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(); // 根据方法签名获取方法 // 然后获取方法上的 @Monitor 注解 Monitor annotation = signature.getMethod().getAnnotation(Monitor.class); // 获取 @Monitor("onClick") 注解中的注解属性 String value = annotation.value(); // 获取方法名称 String className = signature.getDeclaringType().getSimpleName(); // 获取方法所在的类名 String methodName = signature.getName(); // 记录方法执行开始时间 long startTime = System.currentTimeMillis(); // 执行具体的方法 result = joinPoint.proceed(); // 记录方法执行结束时间 long endTime = System.currentTimeMillis(); Log.i(TAG, "执行 " + className + " 中的 " + methodName + " 方法花费了 " + (endTime - startTime) + " ms , 注解属性为 " + value ); } catch (Throwable throwable) { throwable.printStackTrace(); } return result; } }
三、使用 AspectJ 埋点并监控方法性能
监控 public void textClick(View view) 方法性能 , 在该方法上使用 @Monitor 注解 , 该注解已经被定义为切入点 , 所有的包 所有的类 中 , 带有 @com.example.aop_demo.Monitor 注解的方法 , 都是 Pointcut 切入点 , 应用执行时 , 会自动执行埋点业务逻辑 , 这里是在方法执行前后 , 分别记录时间 , 最终计算出方法的耗时 ;
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 { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Monitor("textClick") public void textClick(View view) { // 休眠 500 ms SystemClock.sleep(500); } }
执行结果 : 点击按钮 , 触发 textClick 方法 , 触发了埋点逻辑 , 自动计算出了该方法的执行耗时 ;
2021-09-22 22:23:04.954 12492-12492/com.example.aop_demo I/MonitorAspect: 执行 MainActivity 中的 textClick 方法花费了 501 ms , 注解属性为 textClick