文章目录
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()
本文详细介绍面向切面编程(AOP)的概念及其在Java中的具体应用,包括AspectJ的配置方法、核心语法、切点表达式的使用及多种实际案例,如监听方法调用、限制快速点击等。
1327

被折叠的 条评论
为什么被折叠?



