AspectJ AOP教程:实现Android基于注解无侵入埋点
2019-09-29 本文已影响0人
ImWiki
AOP(Aspect-Oriented Programming),即是面向切面编程,AspectJ是实现AOP的一个重要的框架,它是使用AspectJ编译器(ajc),在编译时期,在关键的的地方插入部分代码,处理相关逻辑,比如可以用于打印方法执行的效率,权限检查等。在Android上的应用主要是做性能监控、基于注解的数据埋点等,Hugo 就是基于AspectJ实现。
教程
修改项目根目录的 build.gradle 文件
buildscript {
dependencies {
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.0'
}
}
在APP和Module的build.gradle增加插件
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// 下面这行不是必须的,但是为了有时候去掉上面插件不报错就需要增加
implementation 'org.aspectj:aspectjrt:1.9.4'
}
创建注解
用于打印日志
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectDebugLog {
}
用于埋点
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectAnalyze {
String name();
}
创建配置
@SuppressWarnings("unused")
@Aspect
public class AspectTrace {
private static AspectTraceListener aspectTraceListener;
/**
* 针对所有继承 Activity 类的 onCreate 方法
*/
@Pointcut("execution(* android.app.Activity+.onCreate(..))")
public void activityOnCreatePointcut() {
}
/**
* 针对带有AspectAnalyze注解的方法
*/
@Pointcut("execution(@com.taoweiji.aspect.trace.AspectAnalyze * *(..))")
public void aspectAnalyzeAnnotation() {
}
/**
* 针对带有AspectDebugLog注解的方法
*/
@Pointcut("execution(@com.taoweiji.aspect.trace.AspectDebugLog * *(..))")
public void aspectDebugLogAnnotation() {
}
/**
* 针对前面 aspectAnalyzeAnnotation() 的配置
*/
@Around("aspectAnalyzeAnnotation()")
public void aroundJoinAspectAnalyze(final ProceedingJoinPoint joinPoint) throws Throwable {
Object target = joinPoint.getTarget();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
AspectAnalyze aspectAnalyze = methodSignature.getMethod().getAnnotation(AspectAnalyze.class);
long startTimeMillis = System.currentTimeMillis();
joinPoint.proceed();
if (aspectTraceListener != null) {
aspectTraceListener.onAspectAnalyze(joinPoint, aspectAnalyze, methodSignature, System.currentTimeMillis() - startTimeMillis);
}
}
/**
* 针对前面 aspectDebugLogAnnotation() 或 activityOnCreatePointcut() 的配置
*/
@Around("aspectDebugLogAnnotation() || activityOnCreatePointcut()")
public void aroundJoinAspectDebugLog(final ProceedingJoinPoint joinPoint) throws Throwable {
long startTimeMillis = System.currentTimeMillis();
joinPoint.proceed();
long duration = System.currentTimeMillis() - startTimeMillis;
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
SourceLocation location = joinPoint.getSourceLocation();
String message = String.format("%s(%s:%s) [%sms]", methodSignature.getMethod().getName(), location.getFileName(), location.getLine(), duration);
if (aspectTraceListener != null) {
aspectTraceListener.logger("AspectTrace", message);
} else {
Log.e("AspectTrace", message);
}
}
public static void setAspectTraceListener(AspectTraceListener aspectTraceListener) {
AspectTrace.aspectTraceListener = aspectTraceListener;
}
public interface AspectTraceListener {
void logger(String tag, String message);
void onAspectAnalyze(ProceedingJoinPoint joinPoint, AspectAnalyze aspectAnalyze, MethodSignature methodSignature, long duration);
}
}
配置
在 MyApplication 设置监听器
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
AspectTrace.setAspectTraceListener(new AspectTrace.AspectTraceListener() {
@Override
public void logger(String tag, String message) {
Log.e(tag, message);
}
@Override
public void onAspectAnalyze(ProceedingJoinPoint joinPoint, AspectAnalyze aspectAnalyze, MethodSignature methodSignature, long duration) {
Log.e("onAspectAnalyze", aspectAnalyze.name());
// TODO 实现统计功能
}
});
}
}
public class MainActivity extends Activity {
@AspectAnalyze(name = "MainActivity.onCreate")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.name).setOnClickListener(v -> onNameClick());
}
@AspectDebugLog
@AspectAnalyze(name = "onNameClick")
public void onNameClick() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@AspectAnalyze(name = "MainActivity.onDestroy")
@Override
protected void onDestroy() {
super.onDestroy();
}
}
结果
E/onAspectAnalyze: MainActivity.onCreate
E/AspectTrace: onNameClick(MainActivity.java:28) [502ms]
E/onAspectAnalyze: onNameClick
E/onAspectAnalyze: MainActivity.onDestroy
原理分析
app/build/intermediates/ajx/debug/includefiles/com/taoweiji/aspectjexample/MainActivity.class
可以看到通过AspectJ的ajc编译器转换后的class,在生成dex文件之前,在.class文件中插入了一些代码,从而实现AOP技术。
public class MainActivity extends Activity {
public MainActivity() {
}
@AspectAnalyze(
name = "MainActivity.onCreate"
)
protected void onCreate(Bundle savedInstanceState) {
JoinPoint var3 = Factory.makeJP(ajc$tjp_0, this, this, savedInstanceState);
AspectTrace var10000 = AspectTrace.aspectOf();
Object[] var5 = new Object[]{this, savedInstanceState, var3};
var10000.aroundJoinAspectAnalyze((new MainActivity$AjcClosure3(var5)).linkClosureAndJoinPoint(69648));
}
@AspectDebugLog
@AspectAnalyze(
name = "onNameClick"
)
public void onNameClick() {
JoinPoint var2 = Factory.makeJP(ajc$tjp_1, this, this);
AspectTrace var10000 = AspectTrace.aspectOf();
Object[] var4 = new Object[]{this, var2};
var10000.aroundJoinAspectAnalyze((new MainActivity$AjcClosure7(var4)).linkClosureAndJoinPoint(69648));
}
@AspectAnalyze(
name = "MainActivity.onDestroy"
)
protected void onDestroy() {
JoinPoint var1 = Factory.makeJP(ajc$tjp_2, this, this);
AspectTrace var10000 = AspectTrace.aspectOf();
Object[] var2 = new Object[]{this, var1};
var10000.aroundJoinAspectAnalyze((new MainActivity$AjcClosure9(var2)).linkClosureAndJoinPoint(69648));
}
static {
ajc$preClinit();
}
}