Android AOP使用

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 initializationstatic块初始化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限制快速点击

使用AOP检查网络

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值