AOP(Aspect-Oriented Programming)蹈胡,即是面向切面編程渊季,AspectJ是實(shí)現(xiàn)AOP的一個重要的框架朋蔫,它是使用AspectJ編譯器(ajc),在編譯時期却汉,在關(guān)鍵的的地方插入部分代碼驯妄,處理相關(guān)邏輯,比如可以用于打印方法執(zhí)行的效率合砂,權(quán)限檢查等青扔。在Android上的應(yīng)用主要是做性能監(jiān)控、基于注解的數(shù)據(jù)埋點(diǎn)等翩伪,Hugo 就是基于AspectJ實(shí)現(xiàn)微猖。
教程
修改項(xiàng)目根目錄的 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'
}
創(chuàng)建注解
用于打印日志
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectDebugLog {
}
用于埋點(diǎn)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectAnalyze {
String name();
}
創(chuàng)建配置
@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 設(shè)置監(jiān)聽器
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 實(shí)現(xiàn)統(tǒng)計功能
}
});
}
}
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();
}
}
結(jié)果
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編譯器轉(zhuǎn)換后的class缘屹,在生成dex文件之前凛剥,在.class文件中插入了一些代碼,從而實(shí)現(xiàn)AOP技術(shù)轻姿。
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();
}
}