[AOP]AspectJX基本使用

AspectJX基于AspectJ并在此基础上扩展出来可应用于Android开发平台的AOP框架,可作用于java源码,class文件及jar包,同时支持kotlin的应用。

引入

  • 插件引用

在项目根目录的build.gradle里依赖AspectJX

dependencies {
    classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.8'
}

或者使用product目录下的jar包,在你的项目根目录下新建目录plugins,把product/gradle-android-plugin-aspectjx-2.0.0.jar拷贝到plugins,依赖jar包

dependencies {
    classpath fileTree(dir:'plugins', include:['*.jar'])
}
  • 在app项目的build.gradle里应用插件
apply plugin: 'android-aspectjx'
//或者这样也可以
apply plugin: 'com.hujiang.android-aspectjx'

AOP可以做什么

  • 日志
  • 持久化
  • 性能监控
  • 数据校验
  • 缓存

AspectJ核心语法简介

AspectJ 其实就是一种 AOP 框架,AOP 是实现程序功能统一维护的一种技术。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合性降低,提高程序的可重用性,同时大大提高了开发效率。因此 AOP 的优势可总结为如下 两点:

  • 无侵入性。
  • 修改方便。

下面介绍一下AspectJ的一些核心概念

  • 横切关注点:对哪些方法进行拦截,拦截后怎么处理
  • 切面(Aspect):对横切关注点的抽象
  • 连接点(JoinPoint):是程序的关键执行点,也是我们关注的点,它是指被拦截到的点(方法、字段、构造器等)
  • 切入点(PointCut):对JoinPoint进行拦截的定义。PointCut的目的是提供一种方法使得开发者能够选择自己感兴趣的JoinPoint
  • 通知(Advice):切入点仅用于捕捉连接点集合,但是,除了捕捉连接点集合以外什么事情都没有做。事实上实现横切行为我们要使用通知。它 一般指拦截到 JoinPoint 后要执行的代码,分为 前置、后置、环绕 三种类型。这里,我们需要注意 Advice Precedence(优先权) 的情况,比如我们对同一个切面方法同时使用了 @Before@Around 时就会报错,此时会提示需要设置 Advice 的优先级。

AspectJ 作为一种基于 Java 语言实现的一套面向切面程序设计规范。它向 Java 中加入了 连接点(Join Point) 这个新概念,其实它也只是现存的一个 Java 概念的名称而已。它向 Java 语言中加入了少许新结构,譬如切入点(pointcut)、通知(Advice)、类型间声明(Inter-type declaration) 和切面(Aspect)。切入点和通知动态地影响程序流程,类型间声明则是静态的影响程序的类等级结构,而切面则是对所有这些新结构的封装。

对于AsepctJ 中的各个核心概念来说,其连接点就恰如程序流中适当的一点。而切入点收集特定的连接点集合和在这些点中的值。一个通知则是当一个连接点到达时执行的代码,这些都是 AspectJ 的动态部分。其实连接点就好比是程序中那一条一条的语句,而切入点就是特定一条语句处设置的一个断点,它收集了断点处程序栈的信息,而通知就是在这个断点前后想要加入的程序代码。

此外,AspectJ中也有许多不同种类的类型间声明,这就允许程序员修改程序的静态结构、名称、类的成员以及类之间的关系。 AspectJ中的切面是横切关注点的模块单元。它们的行为与 Java语言中的类很象,但是切面 还封装了切入点、通知以及类型间声明。

AspectJ的语法

  • JoinPoint
    一般定位在如下位置:
    (1)函数调用
    (2)获取、设置变量
    (3)类初始化
    使用 PointCut 对我们指定的连接点进行拦截,通过Advice,就可以拦截到 JoinPoint 后要执行的代码。Advice 通常有以下 三种类型:
    (1)BeforePointCut 之前执行。
    (2)AfterPointCut 之后执行。
    (3)AroundPointCut 之前、之后分别执行。

示例1,最简单使用:

@Before("execution(* android.app.Activity.on**(..))")    
public void onActivityCalled(JoinPoint joinPoint) throws Throwable {     
   Log.d(...)    
}

其中,在 execution 中的是一个匹配规则,第一个 * 代表匹配任意的方法返回值,后面的语法代码匹配所有 Activity 中以 on 开头的方法。这样,我们就可以 在 App 中所有 Activity 中以 on 开头的方法中输出一句log。

上面的 execution 就是处理 Join Point 的类型,通常有如下两种类型:
(1)call:代表调用方法的位置,插入在函数体外面。
(2)execution:代表方法执行的位置,插入在函数体内部。

示例2,统计 Application 中的所有方法耗时:

@Aspect    
public class ApplicationAop {       
     @Around("call (* com.json.chao.application.BaseApplication.**(..))")        
     public void getTime(ProceedingJoinPoint joinPoint) {    
         Signature signature = joinPoint.getSignature();        
         String name = signature.toShortString();        
         long time = System.currentTimeMillis();        
         try {       
              joinPoint.proceed();        
         } catch (Throwable throwable) {       
              throwable.printStackTrace();        
         }        
         Log.i(TAG, name + " cost" +     (System.currentTimeMillis() - time));        
     }    
}

需要注意的是,当Advice为Before或After时,函数参数为JoinPoint,当为Around时,函数参数为ProceedingJoinPoint。而Around和Before及After最大的区别是,ProceedingJoinPoint不同于JoinPoint,其内部提供了proceed方法来执行目标函数。

参考文章

深入探索编译插桩技术(二、AspectJ)
AOP 之 AspectJ 全面剖析 in Android

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值