文章目录
AOP使用
概述
OOP
面向对象编程:问题或功能都被划分在一个一个点模块里,每个模块专心做自己的事情,模块之间通过设计好的接口交互。
AOP
面向切面编程:由于OOP推崇高内聚、低耦合的风格,导致模块之间的可见性变差,不利于权限拦截、日志输出等功能,AOP技术应用而生,因此AOP是对OOP的补充和完善,将一些功能集中起来进行统一管理。
AspectJ
AspectJ是Java语言实现AOP的一种方案。
APT与AOP
- APT是利用AndroidAnnotation在编译时生成代码,再通过反射将生成代码与项目中代码进行关联;AOP是在编译完成后生成
.dex
文件之前,通过修改.class
文件,操作字节码修改代码逻辑 - APT技术优点:隔离复杂的内部逻辑,简化开发流程;减少重复代码,提高工作效率
- AOP技术优点:功能更强大,使用场景更广,复杂度较高
AspectJ配置
项目根目录下的build.gradle
dependencies {
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.10'
}
模块中的build.gradle
apply plugin : 'android-aspectjx'
dependencies {
implementation 'org.aspectj:aspectjrt:1.9.6'
}
控制AspectJ
//关闭AspectJX功能
aspectjx {
enabled false
}
//AOP配置(exclude 和 include 二选一)
aspectjx {
// 只对以下包名做 AOP 处理
include 'com.example.app'
}
AspectJ介绍
核心语法
- 切面(Aspect):使用
@Aspect
注解定义一个切面类,一个切面是一个独立的功能实现,一个程序可以定义多个切面 - 连接点(JoinPoint):连接点表示程序中可以切入代码的位置,包含:函数的调用和执行,类的初始化,一场处理
- 切入点(PointCut):使用
@Pointcut
注解定义切入点,切入点是具体的连接点,切点定义了需要织入代码的连接点,切点有专门的语法 - 通知(Advice):通知表示对切点的监听,可以在这里织入代码,通知包含:
@Before
方法执行前@After
方法执行后@Around
方法执行前后@AfterReturning
方法返回后之后执行@AfterThrowing
抛出异常时执行
定义切入点
@Pointcut(切点表达式)
JoinPoints | 说明 | 语法 |
---|---|---|
method call | 函数调用 | call(MethodSignature) |
method execution | 函数执行 | execution(MethodSignature) |
constructor call | 构造函数被调用 | call(Constructorsignature) |
constructor execution | 构造函数执行 | execution(constructorSignature) |
field get | 读变量 | get(FieldSignature) |
field set | 写变量 | set(FieldSignature) |
static initialization | static块初始化 | staticinitializattion(TypeSignature) |
handler | 异常处理 | handler(TypeSignature) 只能和@Before()配合使用 |
定义通知
@Before(切点表达式)
Advice | 说明 |
---|---|
@Before(Pointcut) | 在切入点之前执行 |
@After(Pointcut) | 在切入点之后执行 |
@Around(ProceedingJoinPoint) | 替代原来的代码,可以通过ProceedingJoinPoint.procedd() 执行切入点代码不支持@Before() / @After()一起使用 |
@AfterReturning(Pointcut) | 在切入点返回结果之后执行 |
@AfterThrowing(Pointcut) | 在切入点抛出异常之后执行 |
通配符
Signature | 语法 |
---|---|
* | 除“.”以外任意字符串 |
… | 任意参数列表 |
+ | 子类 |
切点表达式
@注解 访问权限 返回值类型 类名.方法名(参数)
语法 | 说明 |
---|---|
@注解 | 注解类的完整路径,可以省略 |
访问权限 | public/private/protected/static/final,可以省略 |
返回值类型 | 如果不限定类型,可以使用通配符* |
类名.方法名 | 可以使用通配符 * 和 … 和 + |
参数 | int(int,char) 表示参数有2个 (String…) 表示至少一个String参数 (Object…) 表示不定个数的参数 |
案例
package com.example.app;
public class User {
public void eat() {
Log.e("AOP", "User#eat()");
}
public String run(String params) {
Log.e("AOP", "User#run()");
return params;
}
}
监听方法调用前和调用后
@Aspect
public class MyAop {
@Pointcut("execution(public * com.example.app.User.*(..))")
public void method() {
}
@Before("method()")
public void onBefore(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
//获取全类名
String className = signature.getDeclaringTypeName();
//获取方法名
String methodName = signature.getName();
Log.e("AOP", "onBefore(): " + className + "#" + methodName);
}
@After("method()")
public void onAfter(JoinPoint joinPoint) {
Signature signature = joinPoint.getSignature();
String className = signature.getDeclaringTypeName();
String methodName = signature.getName();
Log.e("AOP", "onAfter(): " + className + "#" + methodName);
}
}
监听方法执行前后
@Aspect
public class MyAop {
@Pointcut("execution(public * com.example.app.User.eat(..))")
public void eatMethod() {
}
/**
* 注意不要使用try-catch
*/
@Around("eatMethod()")
public void onAround(ProceedingJoinPoint joinPoint) throws Throwable {
Signature signature = joinPoint.getSignature();
//获取全类名
String className = signature.getDeclaringTypeName();
//获取方法名
String methodName = signature.getName();
Log.e("AOP", "onAround-start: " + className + "#" + methodName);
joinPoint.proceed();
Log.e("AOP", "onAround-end");
}
}
监听返回值之后
@Aspect
public class MyAop {
@AfterReturning(pointcut = "execution(public String com.example.app.User.run(..))", returning = "returnValue")
public void onAfterReturning(JoinPoint joinPoint, String returnValue) {
Object[] args = joinPoint.getArgs();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
String[] parameterNames = signature.getParameterNames();
for (int i = 0; i < parameterNames.length; i++) {
Log.e("AOP", "参数 " + parameterNames[i] + ":" + args[i]);
}
Log.e("AOP", "onAfterReturning(): 方法名:" + signature.getName() + ",返回值:" + returnValue);
}
}
匹配setOn开头的方法,在方法执行后操作
@After("execution(* setOn*(..))")
public void onAfter(JoinPoint joinPoint) {
Log.e("TAG", "onAfter()");
}
匹配com.example
包下和子包以to
结尾的方法,在方法执行后操作
@After("execution(* com.example..*to(..))")
public void onAfter(JoinPoint joinPoint) {
Log.e("TAG", "onAfter()");
}
定义切点,在切点执行前后操作
@Pointcut("execution(* com.example.app.User.eat(..))")
public void method() {
}
@Before("method()")
public void onBefore(JoinPoint joinPoint) {
Log.e("TAG", "onBefore()");
}
@After("method()")
public void onAfter(JoinPoint joinPoint) {
Log.e("TAG", "onAfter()");
}
输出:
onBefore()
eat()
onAfter()