• Aspectj基础原理解析


    一、接入和使用

    1、依赖导入

    工程下gradle下

    1. buildscript{
    2. dependencies {
    3. // 用于导入aspectj的plugin
    4. classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
    5. }
    6. }

    对应app或者module的gradle下

    1. // 在当前模块应用aspectj实现字节码插桩
    2. apply plugin: 'android-aspectjx'
    3. // 常用排除一些目录下的代码
    4. aspectjx {
    5. exclude 'versions.9', 'androidx', 'com.google', 'com.taobao', 'com.ut'
    6. }
    7. dependencies {
    8. // 主要导入对应注解和一些通用模板代码
    9. implementation 'org.aspectj:aspectjrt:1.8.9'
    10. }

    2、基础使用(仅简单例子)

    1. // 标记这个类包括需要插入的代码和对应插入位置
    2. @Aspect
    3. public class Aspectj {
    4. // 指定对应的切入点
    5. @Pointcut("execution(* android.com.aspectj.BaseActivity+.onCreate(..)) && within(android.com.aspectj.MainActivity)")
    6. public void activityOnCreatePointcut() {
    7. }
    8. // 在该方法执行前插入
    9. @Before("activityOnCreatePointcut()")
    10. public void activityOnCreateBefore(JoinPoint joinPoint) {
    11. Log.d("xx", "activityOnCreateBefore: " + joinPoint.getThis());
    12. }
    13. // 增强的插入方法
    14. @Around("activityOnCreatePointcut()")
    15. public void activityOnCreateAround(ProceedingJoinPoint joinPoint) throws Throwable {
    16. Log.d("xx", "activityOnCreateAround: " + joinPoint.getThis());
    17. joinPoint.proceed();
    18. }
    19. // 如果After和Around同时存在,After必须在Around之后
    20. @After("activityOnCreatePointcut()")
    21. public void activityOnCreateAfter(JoinPoint joinPoint) {
    22. Log.d("xx", "activityOnCreateAfter: " + joinPoint.getThis());
    23. }
    24. }

    按照Aspectj定下规则,就是可以编写出想要在哪里插入想要的代码,具体的规则说明就不详细的描述了,可以参照AspectJTM 编程指南文档,安卓具体用法会存在不同之处。

    二、基础原理说明

    1、大体的原理

    通过android提示transform的api,操作javac编译出字节码和jar引入的字节码。找到@Aspect标记的类,通过@Pointcut获得我们要插入方法的位置,@Before,@Around,@After标记的方法就是我们要插入的方法(@Aspect对应的类会改变成单例,就可以在对应的位置插入方法)。

    2、解析具体的注解和关键字

    主要分析方式通过查看操作的后的字节码,分析具体插入方法和实现方式

    由于是基于transform的api,可以在Transform的目录找到其加过后的代码

     (1) 使用execution在对应的方法内插入代码配合@Before @After

    1. @Pointcut("execution(* android.com.aspectj.BaseActivity+.onCreate(..)) && within(android.com.aspectj.MainActivity)")
    2. public void activityOnCreatePointcut() {
    3. }
    4. @Before("activityOnCreatePointcut()")
    5. public void activityOnCreateBefore(JoinPoint joinPoint) {
    6. Log.d("xx", "activityOnCreateBefore: " + joinPoint.getThis());
    7. }

     (2)使用call在对应方法调用插入代码配合@Before @After

    1. @Pointcut(
    2. "call(* com.example.app1.TextAspectjCall.call()) && withincode(* com.example.app1.MainActivity.onCreate(..))")
    3. public void callPointcut() {
    4. }
    5. @Before("callPointcut()")
    6. public void call(JoinPoint joinPoint) {
    7. Log.d("xx", "callBefore(call): " + joinPoint.getThis());
    8. }

     (3)@Around增强版的方法插入

    1、配合execution

    生成一个新方法,插入相关代码,放入原先的方法中调用

    1. @Pointcut("execution(* com.example.app1.BaseActivity+.onCreate(..)) && within(com.example.app1.MainActivity)")
    2. public void activityOnCreatePointcut() {
    3. }
    4. @Around("activityOnCreatePointcut()")
    5. public void activityOnCreateAround(ProceedingJoinPoint joinPoint) throws Throwable {
    6. Log.d("xx", "activityOnCreateAround: " + joinPoint.getThis());
    7. joinPoint.proceed();
    8. }

     2、配合call

    在调用处,形成一个新的方法,在这个方法内插入代码,通过调用这个方法,就实现了在调用处实现使用这个@Around插入代码

    1. @Pointcut("call(* com.example.app1.TextAspectjCall.callWithReturn())")
    2. public void callWithReturn() {
    3. }
    4. @Around("callWithReturn()")
    5. public Object call2(ProceedingJoinPoint joinPoint) throws Throwable {
    6. long start = System.currentTimeMillis();
    7. Object result = joinPoint.proceed();
    8. long duration = System.currentTimeMillis() - start;
    9. Log.d("xx", "callWithReturn" + duration);
    10. return result;
    11. }

     以上就是常用4种方案的解析

    三、总结

    Aspectj的基本用法没有什么难度,基本原理也是基于transform api。往深的摸索就是字节码的生成,还有怎么编译的速度。

  • 相关阅读:
    研发费用补贴政策和条件是什么?
    小程序组件概述
    Python如何实现原型设计模式?什么是原型设计模式?Python 原型设计模式示例代码
    <git>如何快速上手并高效协同
    ipc----共享内存
    vue3 element-plus 组件table表格 勾选框回显(初始化默认回显)完整静态代码
    Django 模板的导入与继承
    2022“杭电杯”中国大学生算法设计超级联赛(1)签到题5题
    Oracle(2-2)Oracle Net Architecture
    初识C语言 -- 结构体,分支和循环语句
  • 原文地址:https://blog.csdn.net/m0_37605407/article/details/125418869