鸿蒙开发:实现AOP代码插桩能力

简介: 正确的运用AOP,可以提升代码的模块化、复用性、可维护性和灵活性,同时降低了耦合度,使系统更易于扩展和维护。

前言

本文代码案例基于Api13。

AOP,也就是Aspect Oriented Programming,它是一种编程范式,旨在通过分离横切关注点来提高代码的模块化,将一些常见的关注点,比如日志记录、事务管理、安全控制等从核心业务逻辑中分离出来,使代码更易维护和扩展。

提到AOP,大家最常见的就是日志的记录,AOP可以在不修改原有业务代码的情况下,通过代码插桩的方式,为应用程序添加日志记录功能;当然了,除了日志记录功能,相信大家肯定见过很多的三方的统计,比如友盟,神策等等,他们是怎么来统计的页面的访问量?没错,就是用到了AOP。

AOP,说的简单直白一点,就是,它可以实现对原有的对象方法,在执行前后,进行插桩,同样,在鸿蒙的开发中,我们也可以直接对其方法进行替换操作,如何实现,在Api 11之后使用Aspect对象即可。

方法之前插入函数

addBefore方法,可以在在指定的类对象的原方法执行前插入一个函数,执行顺序就会先执行插入的函数,后执行原有函数。

参数说明

参数名

类型

必填

说明

targetClass

Object

指定的类对象。

methodName

string

指定的方法名,不支持read-only方法。

isStatic

boolean

指定的原方法是否为静态方法,true表示静态方法,false表示实例方法。

before

Function

要插入的函数对象。函数有参数,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;若isStatic为false,则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参数,无参时不做处理。

简单举例

很简单一个案例,有一个对象Test,里面有一个方法,返回一个字符串。

import util from '@ohos.util'
class Test {
  name: string = "AbnerMing"
  getName(): string {
    return this.name
  }
}
@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("点击")
        .onClick(() => {
          let test = new Test()
          console.log("===原始方法获取:" + test.getName())
          util.Aspect.addBefore(Test, "getName", false, (test: Test) => {
            test.name = "程序员一鸣"
          })
          console.log("===追加逻辑后获取:" + test.getName())
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

以上的代码,当执行util.Aspect.addBefore方法后,就会把name进行修改,再次调用test.getName(),就会发生变化,可以看下输出的日志:

当然,你可以在这里,执行任何你需要的逻辑,比如埋点,比如打印日志,比如网络请求等等,都是可以的。

util.Aspect.addBefore(Test, "getName", false, (instance: Test) => {
            instance.name = "程序员一鸣"
            console.log("===打印日志:输出一条日志")
          })


方法之后插入函数


addAfter方法,在指定的类方法执行后插入一段逻辑,最终返回值是插入函数执行后的返回值。


参数说明


参数名

类型

必填

说明

targetClass

Object

指定的类对象。

methodName

string

指定的原方法名,不支持read-only方法。

isStatic

boolean

指定的原方法是否为静态方法,true表示静态方法,false表示实例方法。

after

Function

要插入的函数。函数有参数时,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;若isStatic为false,则为调用方法的实例对象),第二个参数是原方法的返回值(如果原方法没有返回值,则为undefined),其余参数是原方法的参数。函数也可以无参,无参时不做处理。


简单举例


import util from '@ohos.util'
class Test {
  name: string = "AbnerMing"
  getName(): string {
    return this.name
  }
}
@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("点击")
        .onClick(() => {
          let test = new Test()
          console.log("===原始方法获取:" + test.getName())
          util.Aspect.addAfter(Test, "getName", false, (instance: Test) => {
            instance.name = "程序员一鸣"
            console.log("===打印日志:输出一条日志")
            return "程序员大鸣"
          })
          console.log("===追加逻辑后获取:" + test.getName())
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


还是上述的案例,我们把util.Aspect.addBefore换成util.Aspect.addAfter,其它逻辑不变,需要注意的是,最终返回值是插入函数执行后的返回值,也就是意味着,最后的打印是addAfter中的函数返回值,我们看下日志:



替换函数

replace方法,会将指定的类中方法的原方法替换为另一个函数,replace接口执行完成后,只会执行替换后的逻辑,原有的函数逻辑不在执行。

参数说明


参数名

类型

必填

说明

targetClass

Object

指定的类对象。

methodName

string

指定的原方法名,不支持read-only方法。

isStatic

boolean

指定的原方法是否为静态方法,true表示静态方法,false表示实例方法。

instead

Function

要用来替换原方法的函数。函数有参数时,则第一个参数是this对象(若isStatic为true,则为类对象即targetClass;若isStatic为false,则为调用方法的实例对象),其余参数是原方法的参数。函数也可以无参,无参时不做处理。


简单案例


import util from '@ohos.util'
class Test {
  name: string = "AbnerMing"
  getName(): string {
    console.log("===方法中打印")
    return this.name
  }
}
@Entry
@Component
struct Index {
  build() {
    Column() {
      Button("点击")
        .onClick(() => {
          let test = new Test()
          util.Aspect.replace(Test, "getName", false, (instance: Test) => {
            instance.name = "程序员一鸣"
            console.log("===打印日志:输出一条日志")
            return "程序员大鸣"
          })
          console.log("===追加逻辑后获取:" + test.getName())
        })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}


我们在getName方法中打印了一条日志,当我们执行replace方法之后,可以发现并没有执行打印,因为函数已经被替换,原始的函数逻辑就不在执行。



相关总结


正确的运用AOP,可以提升代码的模块化、复用性、可维护性和灵活性,同时降低了耦合度,使系统更易于扩展和维护。

相关文章
|
20天前
|
前端开发
鸿蒙开发:使用Rect绘制矩形
几何矩形,在实际的开发中,有多种的实现方式,并非一定需要Rect组件,但是,如果有需要用到矩形的场景,建议还是使用Rect组件,因为Rect组件自身携带了很多样式属性,可以满足我们日常的不同的需求。
鸿蒙开发:使用Rect绘制矩形
|
20天前
|
人工智能 物联网 Android开发
【04】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-自定义一个设置输入小部件组件-完成所有设置setting相关的页面-优雅草卓伊凡
【04】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-自定义一个设置输入小部件组件-完成所有设置setting相关的页面-优雅草卓伊凡
156 92
|
20天前
|
人工智能 物联网 Android开发
【03】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-在lib目录新建自定义库UtilsLibrary,ComponentLibrary,CommonConstLibrary完成设置SettingsView.ets初始公共类书写-优雅草卓伊凡
【03】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-在lib目录新建自定义库UtilsLibrary,ComponentLibrary,CommonConstLibrary完成设置SettingsView.ets初始公共类书写-优雅草卓伊凡
62 23
【03】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-在lib目录新建自定义库UtilsLibrary,ComponentLibrary,CommonConstLibrary完成设置SettingsView.ets初始公共类书写-优雅草卓伊凡
|
20天前
|
存储 人工智能 物联网
【02】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-登录页面LoginView.ets完成-并且详细解释关于arkui关于 CommonConst, commonColor, InputDataModel-优雅草卓伊凡
【02】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-登录页面LoginView.ets完成-并且详细解释关于arkui关于 CommonConst, commonColor, InputDataModel-优雅草卓伊凡
49 14
【02】优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-登录页面LoginView.ets完成-并且详细解释关于arkui关于 CommonConst, commonColor, InputDataModel-优雅草卓伊凡
|
20天前
|
编译器 Linux iOS开发
华为鸿蒙编译器deveco studio 开发项目如何插入自己的版权代码-单文件添加和设置全局模板-优雅草卓伊凡
华为鸿蒙编译器deveco studio 开发项目如何插入自己的版权代码-单文件添加和设置全局模板-优雅草卓伊凡
54 14
华为鸿蒙编译器deveco studio 开发项目如何插入自己的版权代码-单文件添加和设置全局模板-优雅草卓伊凡
|
20天前
|
人工智能 物联网 编译器
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡
44 11
【01】优雅草星云物联网AI智控系统从0开发鸿蒙端适配完成流程-初始化鸿蒙编译器deveco studio项目结构-UI设计图切片下载-优雅草卓伊凡
|
16天前
|
人工智能 JavaScript 数据安全/隐私保护
鸿蒙开发难题多到崩溃?然而 10 亿终端暗藏财富密码-卓伊凡
鸿蒙开发难题多到崩溃?然而 10 亿终端暗藏财富密码-卓伊凡
44 5
鸿蒙开发难题多到崩溃?然而 10 亿终端暗藏财富密码-卓伊凡
|
4天前
|
人工智能 前端开发 物联网
【05】20250416优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-增加告警中心相关卡片页面WarningCardWidget相关-增加Canvas 绘制折线图-Canvas 绘制柱状图-首页-优雅草卓伊凡
【05】20250416优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-增加告警中心相关卡片页面WarningCardWidget相关-增加Canvas 绘制折线图-Canvas 绘制柱状图-首页-优雅草卓伊凡
23 0
【05】20250416优雅草星云物联网AI智控系统从0开发鸿蒙端适配-deveco studio-增加告警中心相关卡片页面WarningCardWidget相关-增加Canvas 绘制折线图-Canvas 绘制柱状图-首页-优雅草卓伊凡
|
9天前
|
缓存 开发工具 开发者
鸿蒙NEXT开发App相关工具类(ArkTs)
这段代码展示了一个名为鸿蒙NEXT开发 `AppUtil` 的工具类,主要用于管理鸿蒙应用的上下文、窗口、状态栏、导航栏等配置。它提供了多种功能,例如设置灰阶模式、颜色模式、字体类型、屏幕亮度、窗口属性等,并支持获取应用包信息(如版本号、包名等)。该工具类需在 UIAbility 的 `onWindowStageCreate` 方法中初始化,以便缓存全局变量。代码由鸿蒙布道师编写,适用于鸿蒙系统应用开发,帮助开发者更便捷地管理和配置应用界面及系统属性。
|
20天前
|
前端开发
鸿蒙开发:使用Ellipse绘制椭圆
除了使用Ellipse组件可以一个椭圆之外,我们还可以使用Canvas来绘制一个椭圆,但是相对来说,还是没有Ellipse组件高效,所以,如果说Ellipse组件能够满足需求,还是以Ellipse组件为主。
鸿蒙开发:使用Ellipse绘制椭圆

热门文章

最新文章