Android AOP切面编程之:AspectJ (三)字节码分析和应用场景

Android AOP切面编程之:AspectJ (三)字节码分析和应用场景,第1张

1:Android AspectJ 插件集成 1.1:AspectJ版本和 Gradle以及Gradle Tools 版本对应关系

GitHub - HujiangTechnology/gradle_plugin_android_aspectjx: A Android gradle plugin that effects AspectJ on Android project and can hook methods in Kotlin, aar and jar file.

2:AspectJ 语法解析

AspectJ 其实是一种 AOP框架,AOP是实现程序功能统一维护的一种技术,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合性降低,提高程序的可重用性,提高开发效率。

2.1: 切点

切点表示对哪些方法进行拦截,拦截后怎么处理

2.2 :切面(Aspect)

类是对物体特征的抽象,切面就是对横切关注点的抽象

2.3:连接点(JoinPoint)

JPoint 是程序的关键执行点,也是我们关注的重点。它是指被拦截到的点(如方法、字段、构造器等)

2.4:切入点(PointCut)

对 JoinPoint进行拦截的定义,PointCut 的目的是提供一种方法使得开发者能够选择自己感兴趣的 JoinPoint

2.5:  通知(Advice)

切入点仅用于捕捉连接点集合,但是除了捕捉连接点集合外其他什么事情都没做,事实上实现横切行为我们需要使用通知,它一般指拦截到 JoinPoint 后需要执行的代码,分为前置,后置,环绕三种类型。

使用 PointCut 对我们指定的连接点进行拦截,通过 Advice ,就可以拦截到 JoinPoint后要执行的代码,Advice 通常有以下三种类型:

1)Before : PointCut 切点之前执行

2)After:   PointCut 切点之后执行

3)Around: PointCut 之前,之后分别执行

2.6: call 和 execution区别

execution(* android.app.Activity.on**(..))

上述表达式中:execution是一个匹配规则,第一个 * 代表匹配任意方法的返回值,后面语法表示匹配所有 Activity 中以 on开头的 方法,-----》这样我们就可以在 App 中所有 Activity中以 on开头的方法中输出一句log 

1)  call  : 代表调用方法的位置,插入在函数体外面

2)execution: 代表方法执行的位置,插入在函数体内部

3:分析AspectJ插桩字节码 3.1 先看如下插桩AspectJ类源码
@Aspect
public class TestAsject {

    // 定义切点
    @Pointcut("execution(* android.app.Activity+.onCreate(..))")
    public void activityOnCreate() {

    }

    /**
     *   环绕增强
     *    2022-05-07 16:40:05.714 16885-16885/? I/onCreateInjector: MainActivity: enter
     *    2022-05-07 16:40:05.823 16885-16885/? I/onCreate: enter
     * @param point
     */
    @Around("activityOnCreate()")
    public void onCreateInjector(ProceedingJoinPoint point) {
        Object object = point.getTarget();
        Log.i("TestAsject","onCreateInjector: "+ object.getClass().getSimpleName() + ": enter");
        try {
            point.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    /**
     * 前置增强
     * @param joinPoint
     */
    @Before("activityOnCreate()")
    public void onCreateBefore(JoinPoint joinPoint) {
        Log.i("TestAsject", "onCreateBefore: " + joinPoint.getSignature().getDeclaringType() + ":" + joinPoint.getSignature().getDeclaringTypeName());
    }

    /**
     * 后置增强
     * @param joinPoint
     */
    @After("activityOnCreate()")
    public void onCreateAfter(JoinPoint joinPoint) {
        Log.i("TestAsject", "onCreateAfter: " + joinPoint.getSignature().getDeclaringType() + ":"
                + joinPoint.getSignature().getDeclaringTypeName());
    }
}
public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.i("TestAsject",": onCreate enter");
    }
}

打印内容:

1:  先打印连接点的 环绕通知

2:在打印且连接点的  Before通知

3:  然后打印 连接点的 切点

4:最后打印:连接带你的 After通知

2022-05-12 16:45:49.543 16056-16056/? I/TestAsject: onCreateAround: MainActivity: enter
2022-05-12 16:45:49.543 16056-16056/? I/TestAsject: onCreateBefore: class aop.yhw.com.aspectjproject.MainActivity:aop.yhw.com.aspectjproject.MainActivity
2022-05-12 16:45:49.649 16056-16056/? I/TestAsject: :MainActivity onCreate enter
2022-05-12 16:45:49.649 16056-16056/? I/TestAsject: onCreateAfter: class aop.yhw.com.aspectjproject.MainActivity:aop.yhw.com.aspectjproject.MainActivity
3.2:再看如下插桩AspectJ编译的字节码

4:AspectJ使用场景  4.1 :统计Application中所有方法耗时
    @Aspect
    public class ApplicationAop {
    
        @Around("call (* com.json.chao.application.BaseApplication.**(..))")
        public void getTime(ProceedingJoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String name = signature.toShortString();
        long time = System.currentTimeMillis();
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        Log.i(TAG, name + " cost" +     (System.currentTimeMillis() - time));
        }
    }
4.2: 对App 中所有的方法进行 Systrace函数插桩

查看应用中方法的耗时与 CPU 情况

    @Aspect
    public class SystraceTraceAspectj {

        private static final String TAG = "SystraceTraceAspectj";

        @Before("execution(* **(..))")
        public void before(JoinPoint joinPoint) {
            TraceCompat.beginSection(joinPoint.getSignature().toString());
        }
    
        @After("execution(* **(..))")
        public void after() {
            TraceCompat.endSection();
        }
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/916294.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存