Aspectj 在Android中的简单使用(Java + Kotlin)

OOP&AOP

OOP(Object Oriented Programming):面向对象编程。把问题或功能模块化,每个模块处理自己的事。

AOP(Aspect Oriented Programming):面向切面编程。把分散于不同模块中的相同业务放到统一的地方来管理。如:日志记录,业务埋点,持久化,性能监控,数据校验,缓存,权限检查,异常处理等。

AspectJ简介

AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件,在编译期注入代码。代表框架:Hugo(Jake Wharton)

基本概念

Join Points:连接点,程序中可切入的点。如:方法调用时,读取某个变量时

Pointcut:切入点,代码注入的位置,其实就是有条件限定的Join Point,例如只在特定方法中注入代码

Aspect:切面,一个关注点的模块化

Advice:在切入点注入的代码,一般有before、after、around三种类型

Target Object:被一个或多个aspect横切拦截操作的目标对象

Weaving:把Advice代码织入到目标对象的过程

Inter-type declarations:用来个一个类型声明额外的方法或属性

Demo示例

给方法添加性能测试

Java版本

1.添加依赖

Project->bulid.gradle

dependencies {
    ...
    classpath 'org.aspectj:aspectjtools:1.8.13'
    classpath 'org.aspectj:aspectjweaver:1.8.13'
}

Module->build.gradle

dependencies {
    ...
    implementation 'org.aspectj:aspectjrt:1.8.13'
}
// 最后面添加即可
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.5",
                         "-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
            }
        }
    }
}


2.自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PerformanceAnnotation {
    String value();
}

3.自定义切面

@Aspect
public class PerformanceAspect {

    public static final String TAG = PerformanceAspect.class.getSimpleName();

    @Pointcut("execution(@ com.tongjin.aspectj.java.PerformanceAnnotation * *(..))")
    public void performancePointcut(){}

    @Around("performancePointcut()")
    public Object wavePerformancePointcut(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 类名
        String className = methodSignature.getDeclaringType().getSimpleName();
        // 方法名
        String methodName = methodSignature.getName();
        // 功能名
        PerformanceAnnotation behaviorTrace = methodSignature.getMethod().getAnnotation(PerformanceAnnotation.class);
        String value = behaviorTrace.value();
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long duration = System.currentTimeMillis() - start;
        Log.e(TAG, String.format("%s类中%s方法执行%s功能,耗时:%dms", className, methodName, value, duration));
        return result;
    }
}

4.使用

@PerformanceAnnotation("performance")
public void clickMe(View view) {
    Toast.makeText(this, "Click", Toast.LENGTH_SHORT).show();
}

5.日志输出

Kotlin版本

由于java版本添加依赖的方式,在kotlin中不起作用,采用大神方案

1.添加依赖

Project->build.gradle

dependencies {
    ...
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.4'
}

Module->bulid.gradle

apply plugin: 'android-aspectjx'

2.自定义注解

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class PerformanceAnnotation(val value: String)

3.自定义切面

@Aspect
class PerformanceAspect {

    companion object {
        val TAG = PerformanceAspect::class.java.simpleName
    }

    @Pointcut("execution(@ com.tongjin.myapplication.PerformanceAnnotation * *(..))")
    fun performancePointcut() {
    }

    @Around("performancePointcut()")
    @Throws(Throwable::class)
    fun wavePerformancePointcut(joinPoint: ProceedingJoinPoint) {
        val methodSignature = joinPoint.signature as MethodSignature
        // 类名
        val className = methodSignature.declaringType.simpleName
        // 方法名
        val methodName = methodSignature.name
        // 功能名
        val behaviorTrace = methodSignature.method.getAnnotation(PerformanceAnnotation::class.java)
        val value = behaviorTrace.value
        val start = System.currentTimeMillis()
        joinPoint.proceed()
        val duration = System.currentTimeMillis() - start
        Log.e(TAG, "${className}类中${methodName}方法执行${value}功能,耗时:${duration}ms")
    }
}

4.使用

@PerformanceAnnotation("performance")
fun clickMe(view: View) {
    Toast.makeText(this, "Click", Toast.LENGTH_SHORT).show()
}

5.日志输出

你可能感兴趣的:(java)