Android-设计模式与项目架构-01-编译插桩技术-综述

176 阅读6分钟

编译插桩技术是指在编译时、类加载时或运行时,向原有代码中插入额外代码的技术。这种技术可以在不修改源代码的情况下,增强应用程序的功能,如性能监控、日志记录、方法调用跟踪等。

  • 编译时插桩:在源代码编译时插入代码。这通常通过修改编译器或使用 APT 来实现。
  • 类加载时插桩:在类加载到 JVM 时,通过修改字节码插入额外代码。这可以通过 Java 的 java.lang.instrument 包实现。
  • 运行时插桩:在应用程序运行时动态插入代码,通常使用代理模式或字节码操作库(如 ASM、Javassist)实现。

应用场景

  • 性能监控:在方法进入和退出时插入代码,记录执行时间。
  • 安全检查:在敏感方法调用前插入权限验证逻辑。
  • 调试和分析:插入代码以跟踪变量值、方法调用栈等。

1)、APT(Annotation Process Tools) :用于生成 Java 代码。
2)、AOP(Aspect Oriented Programming):用于操作字节码。

1、APT(Annotation Process Tools)

APT 是 Java 编译器提供的一种工具,用于在编译时扫描和处理注解。通过 APT,开发者可以在编译时生成额外的源代码、配置文件或其他资源。

  • 工作机制:APT 在编译时会扫描源码中的注解,并调用注解处理器(Annotation Processor)对这些注解进行处理。处理器可以生成新的源代码或修改现有代码。
  • 常见用途:APT 经常用于简化开发,减少样板代码。例如,使用 APT 自动生成 Builder 类、DAO 类或其他重复性的代码。

应用场景

  • 代码生成:通过注解生成 getter/setter 方法、构造函数、接口实现等。
  • 配置文件生成:自动生成 META-INF/services 文件,以支持 SPI 机制(如 AutoService)。
  • 框架集成:如 Dagger、ButterKnife 等,使用 APT 在编译时生成依赖注入代码。

1.1 系列目录

Android-设计模式-01-编译插桩技术- APT(编译期注解处理器)-Java 版本

Android-设计模式-01-编译插桩技术- APT(编译期注解处理器)-kotlin+kapt版本

Android-设计模式-01-编译插桩技术- APT(编译期注解处理器)-kotlin+ksp版本

2、AOP(Aspect Oriented Programming)

AOP 是一种编程范式,用于实现横切关注点的模块化。在 AOP 中,通过切面(Aspect)将横切关注点的代码从业务逻辑中分离出来,并在运行时或编译时织入到目标代码中。

  • 运行时 AOP:通常使用代理模式(如 Spring AOP)在运行时动态地将切面代码插入到目标方法的前后或周围。在应用程序运行时动态插入代码,通常使用代理模式或字节码操作库(如 ASM、Javassist)实现.

  • 编译时 AOP:使用像 AspectJ 这样的工具在编译时将切面代码织入目标代码中,生成的字节码已经包含了横切关注点的代码。

编译时AOP 是在编译完成后生成 dex 文件之前的时候,直接通过修改 .class 文件的方式,来直接添加或者修改代码逻辑的。

而对于操作字节码的方式来说,一般都在 代码监控、代码修改、代码分析 这三个场景有着很广泛的应用。

相对于 Java 代码生成的方式,操作字节码的方式有如下 特点:

  • 1)、应用场景更广。
  • 2)、功能更加强大。
  • 3)、使用复杂度较高。

此外,我们不仅可以操作 .class 文件的 Java 字节码,也可以操作 .dex 文件的 Dalvik 字节码

2.1、代码监控

编译插桩技术除了 不能够实现耗电监控,它能够实现各式各样的性能监控,例如:网络数据监控、耗时方法监控、大图监控、线程监控 等等。

譬如 网络数据监控 的实现,就是在 网络层通过 hook 网络库方法 和 自动化注入拦截器的形式,实现网络请求的全过程监控,包括获取握手时长,首包时间,DNS 耗时,网络耗时等各个网络阶段的信息

实现了对网络请求过程的监控之后,我们便可以 对整个网络过程的数据表现进行详细地分析,找到网络层面性能的问题点,并做出针对性地优化措施。例如针对于 网络错误率偏高 的问题,我们可以采取以下几方面的措施,如下所示:

  • 1)、使用 HttpDNS。
  • 2)、将错误日志同步 CDN。
  • 3)、CDN 调度链路优化。

2.2、代码修改

用编译插桩技术来实现代码修改的场景非常之多,而使用最为频繁的场景具体可细分为为如下四种:

  • 1)、实现无痕埋点网易HubbleData之Android无埋点实践51 信用卡 Android 自动埋点实践%E3%80%82)
  • 2)、统一处理点击抖动:编译阶段统一 hook android.view.View.OnClickListener#onClick() 方法,来实现一个快速点击无效的防抖动效果,这样便能高效、无侵入性地统一解决客户端快速点击多次导致频繁响应的问题。
  • 3)、第三方 SDK 的容灾处理:我们可以在上线前临时修改或者 hook 第三方 SDK 的方法,做到快速容灾上线。
  • 4)、实现热修复框架:我们可以在 Gradle 进行自动化构建的时候,即在 Java 源码编译完成之后,生成 dex 文件之前进行插桩,而插桩的作用是在每个方法执行时先去根据自己方法的签名寻找是否有自己对应的 patch 方法,如果有,执行 patch 方法;如果没有,则执行自己原有的逻辑。

2.3、代码分析

例如 Findbugs 等三方的代码检查工具里面的 自定义代码检查 也使用了编译插桩技术,利用它我们可以找出 不合理的 Hanlder 使用、new Thread 调用、敏感权限调用 等等一系列编码问题。

3. 总结

  • APT 主要用于编译时自动生成代码,简化开发者的工作,常见于依赖注入框架和代码生成工具中。
  • AOP 主要用于运行时或编译时自动织入横切关注点代码,提高代码的模块化程度,常用于日志、事务、权限控制等方面。
  • 编译插桩 是一种通用的技术手段,用于在编译时、类加载时或运行时向目标代码中插入额外逻辑,适用于性能监控、调试、分析等场景。