stdx.aspectCJ

功能介绍

stdx.aspectCJ 包提供了 Cangjie 中面向切面编程(Aspect Oriented Programming, AOP)的相关注解,配合 libcollect-aspects 和 libwave-aspects 两个编译插件使用,可以对函数进行前后插桩以及替换实现。

API 列表

类名功能
InsertAtEntry一个注解类,提供一种切面能力。在注解所指定方法的入口,织入对被注解标注的函数的调用。
InsertAtExit一个注解类,提供一种切面能力。在注解所指定方法的退出点,织入对被注解标注的函数的调用。
ReplaceFuncBody一个注解类,提供一种切面能力。将注解所指定方法的方法体,替换为对被注解标注的函数的调用。

规格和使用

规格

标注范围:

  • 注解暂不支持标注在泛型函数上,也不支持织入泛型函数;
  • 注解只允许标注在 public 函数上;
  • 注解可以标注在全局函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在静态成员函数上,支持:
    • 织入另一个全局函数,
    • 织入另一个实例成员函数,
    • 织入另一个静态成员函数;
  • 注解可以标注在实例成员函数上,支持:
    • 织入同类型的其它实例成员函数。

全局变量定义约束:

  • 定义了切面的包中,只允许定义基本类型(整型、浮点、Rune、Bool)字面值的全局变量,否则编译报错;若需要使用超规格的全局变量,需要将其定义在另外的包再导入使用,以避免在编译后可能产生的循环依赖;

形参约束:

  • 被标注 @InsertAtEntry/@InsertAtExit 的函数,其返回类型只能是 Unit;
  • 被标注 @ReplaceFuncBody 的函数,其返回类型应和被织入的函数的返回类型相同;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果没有形参,那么其织入后总是被无参调用 ;
  • 被标注 @InsertAtEntry/@InsertAtExit/@ReplaceFuncBody 的函数如果有形参,其形参列表应和被织入函数的源码形参列表相同,此外:
    • 特别地,如果被织入的函数是实例成员函数,那么需要将 this 参数显式地写在形参中;
    • 对于被标注 @ReplaceFuncBody 的函数,需要额外添加一个形参,形参的类型和被织入的函数相同,该形参表示被织入函数原始版本的闭包。

使用

要实现 AOP 的完整功能,除了使用上述的注解类来定义切面,还需要两个编译插件:

  • libcollect-aspects.so(.dll/.dylib)
  • libwave-aspects.so(.dll/.dylib)

这两个编译插件以动态库的形式在 stdx.aspectCJ 中提供,不同平台提供不同版本。

应先使用 libcollect-aspects,在编译时收集所有切面、连接点信息;再使用 libwave-aspects 进行二次编译,把之前收集的切面织入到连接点。