AOP (aspect-oriented Programming), that is, section-oriented Programming, AspectJ is an important framework to implement AOP, it is the use of AspectJ compiler (AJC), in the compilation period, in the key place to insert part of the code, processing related logic, For example, efficiency can be used for printing method execution, permission checking, and so on. The main applications on Android are performance monitoring, annotation-based data burial points, etc. Hugo is implemented based on AspectJ.
The tutorial
Modify the build.gradle file in the project root directory
buildscript {
dependencies {
classpath 'com. Hujiang. Aspectjx: gradle - android plugin - aspectjx: 2.0.0'}}Copy the code
Add plug-ins to build.gradle in APP and Module
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'] // The following line is not necessary, but in order to sometimes remove the above plugins without error we need to add implementation'org. Aspectj: aspectjrt: 1.9.4'
}
Copy the code
Create annotation
Used to print logs
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectDebugLog {
}
Copy the code
Used for buried
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AspectAnalyze {
String name();
}
Copy the code
Create a configuration
@SuppressWarnings("unused") @Aspect public class AspectTrace { private static AspectTraceListener aspectTraceListener; /** * onCreate for all inherited Activity classes */ @pointcut ("execution(* android.app.Activity+.onCreate(..) )")
public void activityOnCreatePointcut() {} /** * For methods with AspectAnalyze annotations */ @pointcut ()"execution(@com.taoweiji.aspect.trace.AspectAnalyze * *(..) )")
public void aspectAnalyzeAnnotation() {} /** * for methods with AspectDebugLog annotations */ @pointcut ()"execution(@com.taoweiji.aspect.trace.AspectDebugLog * *(..) )")
public void aspectDebugLogAnnotation() {} /** * For the previous configuration of 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); }} /** * For the previous configuration of aspectDebugLogAnnotation() or 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); }}Copy the code
configuration
Set the listener in 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 implements statistics}}); }}Copy the code
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(); }}Copy the code
The results of
E/onAspectAnalyze: MainActivity.onCreate
E/AspectTrace: onNameClick(MainActivity.java:28) [502ms]
E/onAspectAnalyze: onNameClick
E/onAspectAnalyze: MainActivity.onDestroy
Copy the code
Fundamental analysis
app/build/intermediates/ajx/debug/includefiles/com/taoweiji/aspectjexample/MainActivity.class
You can see that the class transformed by AspectJ’s AJC compiler inserts some code into the.class file to implement the AOP technology before generating the dex file.
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();
}
}
Copy the code