HarmonyOS主要通过插桩机制来实现切面编程,并提供了Aspect类,包括addBefore、addAfter和replace接口。这些接口可以在运行时对类方法进行前置插桩、后置插桩以及替换实现,为开发者提供了更灵活的操作方式。在具体业务场景中,不同的需求可能需要不同的埋点功能和日志记录。通过调用addBefore、addAfter和replace接口,可以实现对类方法的各种功能增强和定制化需求。
针对方法执行时间和次数统计的需求,可以在方法执行前和执行后分别插入统计逻辑,记录方法的执行时间和次数。通过addBefore和addAfter接口的组合运用,可以方便地实现对方法执行情况的监控和统计,为性能优化提供数据支持。
addBefore、addAfter、replace接口的原理基于class的ECMAScript语义,即类的静态方法是类的属性,类的实例方法是类的原型对象(prototype)的属性。
"image.png" (https://wmprod.oss-cn-shanghai.aliyuncs.com/c/user/20241004/135a44bf26b4779f9fe49a41434f304a.png)
针对统计方法耗时和方法执行次数,通过在方法前插入调用次数自增的逻辑,addBefore可以用于统计调用次数。对于执行时间的统计,我们可以利用addBefore记录开始时间,而用addAfter记录结束时间。为了存储执行次数和执行时间,可以利用闭包变量或者其他能够覆盖每次执行的变量的生命周期。
可以参考下面代码:
// somePackage.ets
export class Test {
doSomething() { // 实例方法
// ...
}
static test() { // 静态方法
// ...
}
}
// index.ets
import {Test} from './somePackage'
import util from '@ohos.util';
@Entry
@Component
struct Index {
build() {
// UI代码
…
}
}
// 插入执行前后打印时间, 将插入动作封装成一个接口
function addTimePrinter(targetClass: Object, methodName: string, isStatic: boolean) {
let t1 = 0;
let t2 = 0;
util.Aspect.addBefore(targetClass, methodName, isStatic, () => {
t1 = new Date().getTime();
});
util.Aspect.addAfter(targetClass, methodName, isStatic, () => {
t2 = new Date().getTime();
console.log("t2---t1 = " + (t2 - t1).toString());
});
}
// 给Test的doSomething实例方法添加打印执行时间的逻辑
addTimePrinter(Test, 'doSomething', false);
new Test().doSomething()
// 给Test的test静态方法添加打印执行时间的逻辑
addTimePrinter(Test, 'test', true);
Test.test()