概述:
AOP(Aspect Oriented Program)面向切面编程,在预编译期或者运行期动态修改原有类、方法的代码逻辑实现的技术。
功能:
- 日志
- 持久化
- 数据校验
- 性能监控
- 缓存
- 其它更多
AspectJ 名词
JPoint:代码中可以切入的点。例如:方法、构造函数、Field等
PointCut:用来描述Jpoint切入点的正则表达式,有Advice识别,特定的语法结构构成。
Advice:执行描述,修饰在代码执行前、执行后、或者替代原有代码
Aspcet:切面,由PointCut和Aspect合在一起称作 Aspect
1、JPoint
JPoint 表示类中有哪些地方可以作为切入。包含以下表中的:
JPoint | 说明 |
method call | 函数被调用 |
method execution | 函数执行 |
constructor call | 调用构造函数 |
contractor execution | 执行构造函数 |
filed get | 读“变量” |
filed set | 写“变量" |
pre-initialization | 与初始构造函数 |
initialzation | 初始化构造函数 |
static initialization | static 快初始化 |
handler | 异常处理 |
advice execution | advice 执行 |
2、PointCut
JPoint 的正则表达式,用于识别代码中能够切入的代码片段。
PointCut | 说明 |
call(MethodSignature | ConstructorSingature) | 方法或者构造函数被调用了 |
execution(MethodSignature | ConstructorSingature) | 方法或者构造函数执行了内部代码 |
get(FiledSignature) | 变量被读取了 |
set(FiledSingature) | 变量被写入了 |
preinitialization(ConstructorSignature) | 预初始化构造函数 |
initialization(Constructor) | 初始化构造函数 |
staticinitialization(TypeSignature) | 初始化静态代码块被 |
handler(TypeSignature) | 处理异常 注:只能与Advice 中的@Before使用 |
adviceexecution() | advice 被执行 |
对于PointCut 中的
Signature
正则表达式语法包含以下
Signature | 语法 |
MethodSignature | @注解 访问权限 返回值 类名.方法名(参数) |
ConstructorSignature | @注解 访问权限 类名.new(参数) |
FieldSignature | @注解 访问权限 变量类型 类名.成员变量 |
TypeSignature | 类名 |
语法详细说明:
@注解:
注解的完整路径,PointCut匹配时检测JPoint是否有此注解。
可省略
访问权限:
Java 中的public、protect、private 修饰访问权限,以及staic/final。如果没有可省略,PointCut 会匹配所有权限修饰的JPoint.
1、如果JPoint 切入点带有static或者final,必须是 [权限 static/ final]。
例如:public static 或 public final ,那PointCut 语法中必须是public staic 或者public final
2、在知道权限修饰符是,PointCut 会匹配包含static/final 修饰的JPoint
例如: public void test(), PointCut 中会匹配public final void test() 或public static void test()方法。
返回值:
返回的数据类型,自定义队形需要带上完整路径。如果不限定类型,使用
*通配符代替。
类名:
指定类的完整路径。可以使用通配符代替,包含*、..和+
*:用于匹配出.以外的任意字符
..:表示当前包下的任意子包
+:表示子包
例如:
java.*.Date: 可以表示java.sql.Date,也可以表示java.util.Date
Test*:表示所有已Test开头的类
Java..*:表示java 任意子类
java..*Model+:表示java任意package中名称以Model结尾的子类,比如TabellaModel, TreeModel等
函数名:
函数名包含方法和构造函数。方法名可以使用通配符
*代替。
1、ConstrucorSignature 的构造函数只能为new
2、函数名可以不写,可是用注解来匹配
3、不能使用..通配符开头
变量:
成员变量类型,可以使用* 通配符代替,表示任意类型。
参数:
方法、构造函数的参数类型。
1、(int, char): 表示参数只有两个,并且第一个参数类型是int,第二个参数类型是char
2、(String, ..):表示至少一个参数。并且第一个参数类型是String,后面参数不限。在参数匹配汇中,
..表示任意参数个数和类型。
3、(Object ...):表示不定个数的参数,并且类型是Object。这里的...不是通配符,而是Java中的可变参数。
PointCut 除了单个使用外,还可以使用&&、|| 或!符合使用。&&、||、!的语义同Java中的&&、||、!。
3、Advice
Advice 将需要切入的代码切入到原有代码之前、之后、替换、正常返回之前或者异常之后
Advice | 说明 |
@Before (PointCut) | 在JPoint 之前执行 |
@After (PointCut) | 在JPoint 只后执行 |
@Around (PointCut) | 替换JPoint 的执行代码,如果需要执行原有的代码逻辑,需要使用ProceedingJointPoint.proceed(). 另外:@Before 和 @After 不支持proceed()方法 |
@AfterReturning | 在JPoint 正常执行后执行 语法: @AfterReturning(pointcut="xxx", returning = "value") |
@AfterThrowing | 在JPoint 异常执行后执行 语法: @AfterThrowing(pointcut="xxx", throwing="throwable") |
除了上面说到的JPoint外,AspectJ 还提供了间接的JPoint
JPoint | 说明 |
within(TypePatten) | 表示某个包或者类中包含的JPoint。 TypePatten: 包或者类,可以使用通配符,上面包说明的通配符都可用。 例: within(Test):表示Test中(包括内部类)所有的JPoint。 |
withcode(ConstructorSignature | MethodSignature | 表示某个函数或者构造方法执行过程中涉及到的JPoint 例: withcode("* Test.testMethod(..)"): Test类中testMethod涉及到的JPoint withcode("* Test.new(int , char)"): Test类中包含两个参数(参数类型为int和char)的构造方法所涉及的JPoint |
cflow(PointCuts) | JPoint 的调用控制流,包含JPoint 本身。 |
cflowbleow(PointCuts) | 同cflow,但是不包含JPoint本身 |
this(Type) | 判断Tpye是否是某种类型,即是否满足instanceof Type判断。JPoint代码端(不论是函数、异常处理、static block),从语法上说,它都属于一个类。如果这个类的类型是Type标示的类型,则和他相关的JPoint将全部选中。 |
target(Type) | JPoint 的Target对象是Type类型。与this 相对。不过Target一般用在call的情况,call一个函数,这个函数可能定义在其他类。比如TestMethod是在Test类中定义的,那么target(Test)就会搜索到调用testMethod的地方,但是不包含testMethod的excutionJpoint。 |
args(TypeSignature) | 对JPoint的参数进行搜索。 例如: args(int, ..) 表示第一个参数是int,后面参数个数和类型不想的JPoint |
参考:
1、官网
官网Demo:
官网API:
官网教程:
官网开发要点:
官网文档:
2、博客: