Android AOP programming -- the use of AspectJ

What is AOP

The following is an introduction to AOP on Wikipedia:

Aspect oriented programming (AOP) is a programming idea in computer science, which aims to further separate crosscutting concerns from business subjects, so as to improve the modularization of program code. By adding an additional Advice mechanism to the existing code, the code blocks declared as "pointcuts" can be uniformly managed and decorated, such as "adding background logs to all methods whose method names begin with 'set *". This idea enables developers to add functions (such as log function) that are not closely related to the core business logic of the code to the program without reducing the readability of the business code. Aspect oriented programming idea is also the basis of aspect oriented software development.

Aspect oriented programming divides code logic into different modules (i.e. concerns, a specific logical function). Almost all programming ideas involve the classification of code functions, encapsulating each Concern into independent abstract modules (such as functions, procedures, modules, classes and methods), which can be further implemented, encapsulated and rewritten. Some concerns "crosscutting" several modules in the program code, that is, they appear in multiple modules, which are called crosscutting concerns (horizontal concerns).

What is AspectJ

The following is an introduction to AspectJ on Wikipedia:

AspectJ is in PARC Aspect oriented programming (AOP) extensions created for the Java programming language. It's in Eclipse Foundation Available in open source projects, it can be used independently or integrated into Eclipse. By emphasizing the simplicity and usability of end users, AspectJ has become a widely used AOP de facto standard. Since its first public release in 2001, it uses Java like syntax and includes IDE integration for displaying crosscutting structures.

Use of AspectJ in Android

This article mainly records the use of AspectJ in Android, so it will not record the knowledge points related to the installation of AspectJ and the compilation of aj files using AspectJ. If you need to understand this knowledge, you can refer to the knowledge written by Mr. Deng Fanping In depth understanding of Android AOP.

The following is an example to illustrate the use of AspectJ in Android:

For example, we want to start printing a line of log in the onCreate life cycle method of an Activity. Of course, you can directly code it, but if you use AspectJ aspect oriented programming, you can do this:

  1. Build. In the root directory of the Android project Add the following code to the gradle file
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.2"
        classpath 'org.aspectj:aspectjtools:1.9.7'
        classpath 'org.aspectj:aspectjweaver:1.9.7'
    }
  1. In APP / build Add the following code to the gradle file
android {
	...
}

dependencies {
    implementation 'org.aspectj:aspectjrt:1.9.7'
    ...
}

import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main

final def log = project.logger
final def variants = project.android.applicationVariants

variants.all { variant ->
    if (!variant.buildType.isDebuggable()) {
        log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
        return;
    }
    JavaCompile javaCompile = variant.javaCompile
    javaCompile.doLast {
        String[] args = ["-showWeaveInfo",
                         "-1.8",
                         "-inpath", javaCompile.destinationDir.toString(),
                         "-aspectpath", javaCompile.classpath.asPath,
                         "-d", javaCompile.destinationDir.toString(),
                         "-classpath", javaCompile.classpath.asPath,
                         "-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
        log.debug "ajc args: " + Arrays.toString(args)
        MessageHandler handler = new MessageHandler(true);
        new Main().run(args, handler);
        for (IMessage message : handler.getMessages(null, true)) {
            switch (message.getKind()) {
                case IMessage.ABORT:
                case IMessage.ERROR:
                case IMessage.FAIL:
                    log.error message.message, message.thrown
                    break;
                case IMessage.WARNING:
                    log.warn message.message, message.thrown
                    break;
                case IMessage.INFO:
                    log.info message.message, message.thrown
                    break;
                case IMessage.DEBUG:
                    log.debug message.message, message.thrown
                    break;
            }
        }
    }
}
  1. Create a Java class and annotate it with @ Aspect, as shown in the following code
import android.util.Log;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class MethodAspect {

    private static final String TAG = "MethodAspect";

    @Pointcut("execution(* com.example.testaspectj.MainActivity.onCreate(..))")
    public void jointPoint() {}

    @Before("jointPoint()")
    public void beforeOnCreate() {
        Log.e(TAG, "this message is printed before onCreate...");
    }

}
  1. Run the code to start MainActivity. MainActivity directly uses the code when creating a new Android project without making any changes. After the program runs, the console will print as follows:

    In the app/build/intermediates/javac/debug/classes / directory, you can see mainactivity Class file, decompiled by Android studio, the source code is as follows:

    You can see that a new line of code is inserted into the onCreate method:
MethodAspect.aspectOf().beforeOnCreate();

AspectJ knowledge points

AspectJ terminology

  • JointPoint: the point where code can be injected, such as the calling place of a method or inside the method, "read, write" variables, etc.
  • Pointcut: an expression used to describe the JPoint injection point. For example, where the fly method of Animal class is called, call(* Animal.fly(...)).
  • Advice: Before, After, Around, etc. are common, indicating that the target code is replaced Before and After code execution, that is, where the code is injected into the Pointcut.
  • Aspect: Pointcut and Advice together are called aspect.

AspectJ syntax


Signature reference in Pointcut:

The above Signature is composed of an expression, and there is a "space" between each keyword. The following is the explanation of the keyword:

Once you are familiar with Pointcut syntax, Advice is very simple. It includes the following:


AspectJ applications in Android can also use this open source library: https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx This library simplifies the threshold of using AspectJ directly in Android projects, but there are requirements for the version of gradle plug-in (the maximum version of gradle plug-in currently supported is 3.6.1)

reference resources

Keywords: Java Android AOP aspectj

Added by Ludo Lambrechts on Tue, 25 Jan 2022 04:41:30 +0200