鸿蒙之应用切面编程设计--插桩(1)

2025-06-30 14:38:13
114次阅读
0个评论

前言

大家好,我是青蓝逐码组织的君莫笑。今天给大家介绍一下鸿蒙中插桩的用法,主要以demo演示插桩功能。

概述

切面编程(AOP)通过预编译和运行期间动态代理实现程序功能的统一维护。AOP将程序的关注点分离,通过插入代码实现横切关注点,隔离业务逻辑的各部分,降低耦合度,提高可维护性和可重用性,提升开发效率。

在AOP中,定义切面(aspect)封装横切关注点,无需直接修改业务逻辑代码。这种方式在不修改源代码的前提下添加功能,常用于剥离业务代码和非业务代码,如参数校验、日志记录、性能统计等,以实现更好的代码解耦。

HarmonyOS主要通过插桩机制来实现切面编程,并提供了Aspect类,包括addBefore、addAfter和replace接口。这些接口可以在运行时对类方法进行前置插桩、后置插桩以及替换实现,为开发者提供了更灵活的操作方式。在具体业务场景中,不同的需求可能需要不同的埋点功能和日志记录。通过调用addBefore、addAfter和replace接口,可以实现对类方法的各种功能增强和定制化需求:

  • 对于方法校验类的需求,可以在方法执行前或执行后进行参数校验,确保参数和返回值的合法性。
  • 针对方法执行时间和次数统计的需求,可以在方法执行前后插入统计逻辑,记录执行时间和次数。通过组合使用addBefore和addAfter接口,可以方便地实现方法执行情况的监控和统计,为性能优化提供数据支持。
  • 对于替换类需求,使用AOP的replace接口,动态替换原有方法的实现逻辑。这种机制可在不改变原有方法调用的情况下,实现方法功能的替换或增强,便于项目功能扩展。
  • 针对拉起应用时获取目标包名信息的需求,可以在应用启动时获取并记录目标包名信息。通过调用addBefore接口,实现应用启动过程的监控和记录,为性能优化和故障排查提供帮助。

插桩原理介绍

此处不赘述,点击标题跳转查看。

Aspect的使用

Aspect类用于封装提供切面能力(Aspect Oriented Programming,简写AOP)的接口,这些接口可用于对类方法进行前后插桩或替换实现。

addBefore(前置)

在指定的类对象的原方法执行前插入一个函数。执行addBefore接口后,先运行插入的函数逻辑,再执行指定类对象的原方法。即原方法执行前先运行插入的函数逻辑再执行原方法

参数:

参数名 类型 必填 说明
targetClass Object 指定的类对象。
methodName string 指定的原方法名,不支持read-only方法。
isStatic boolean 指定的原方法是否为静态方法。true表示静态方法,false表示实例方法。
before Function 要插入的函数对象。函数有参数,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;若isStatic为false,则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参数,无参时不做处理。

类对象为非静态函数时

demo演示:

import { util } from '@kit.ArkTS';

class MyClass {
  msg: string = '你好';

  showMsg() {
    return this.msg
  }
}

@Entry
@Component
struct Index {
  @State myClass: MyClass = new MyClass();

  aboutToAppear(): void {

  }

  build() {
    Column() {
      Button('正常执行')
        .onClick(() => {
          AlertDialog.show({ message: JSON.stringify(this.myClass.showMsg(), null, 2) })
        })
      Button('点我实行非静态类前置插桩')
        .onClick(() => {
          // targetClass:指定类对象
          // methodName:指定的原方法名
          // isStatic:是否为静态函数
          // before :要插入的函数对象
          // 函数有参数,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;
          // 若isStatic为false,
          // 则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参数,无参时不做处理。
          util.Aspect.addBefore(MyClass, 'showMsg', false, (instance: MyClass) => {
            instance.msg = '我改变了参数'
          })
          AlertDialog.show({
            message: JSON.stringify('showMsg' + this.myClass.showMsg() + 'msg' + this.myClass.msg, null, 2)
          })
        })
    }
  }
}

1.jpg

可以看到我点击按钮后确实修改了参数

注意:该demo需要使用真机,预览器会失效!

类对象为静态函数时

demo演示:

import { util } from '@kit.ArkTS';

class MyClass {
  msg: string = '你好';

  showMsg() {
    return this.msg
  }

  static staticFun() {
    AlertDialog.show({ message: JSON.stringify('我后执行', null, 2), alignment: DialogAlignment.Bottom })
  }
}

@Entry
@Component
struct Index {
  @State myClass: MyClass = new MyClass();

  aboutToAppear(): void {

  }

  build() {
    Column() {
      Button('正常执行')
        .onClick(() => {
          AlertDialog.show({ message: JSON.stringify(this.myClass.showMsg(), null, 2) })
        })
      Button('点我实行非静态类前置插桩')
        .onClick(() => {
          // targetClass:指定类对象
          // methodName:指定的原方法名
          // isStatic:是否为静态函数
          // before :要插入的函数对象
          // 函数有参数,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;
          // 若isStatic为false,
          // 则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参数,无参时不做处理。
          util.Aspect.addBefore(MyClass, 'showMsg', false, (instance: MyClass) => {
            instance.msg = '我改变了参数'
          })
          AlertDialog.show({
            message: JSON.stringify('showMsg' + this.myClass.showMsg() + 'msg' + this.myClass.msg, null, 2)
          })
        })
      Button('点我实行静态类前置插桩')
        .onClick(() => {
          // targetClass:指定类对象
          // methodName:指定的原方法名
          // isStatic:是否为静态函数
          // before :要插入的函数对象
          // 函数有参数,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;
          // 若isStatic为false,
          // 则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参数,无参时不做处理。
          util.Aspect.addBefore(MyClass, 'staticFun', true, (targetClass: object) => {
            AlertDialog.show({ message: JSON.stringify('我先执行了', null, 2), alignment: DialogAlignment.Top })
          })
          MyClass.staticFun()
        })
    }
  }
}

2.jpg

收藏00

登录 后评论。没有帐号? 注册 一个。