[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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于AOP框架的基本代码,以下是一些可能的实现方式: 1. 定义切面类 切面类是AOP框架中的核心组件,它负责定义切点和切面逻辑。以下是一个简单的切面类示例: ``` public class LoggingAspect { @Before("execution(* com.example.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Before executing " + joinPoint.getSignature().getName() + " method"); } @After("execution(* com.example.*.*(..))") public void logAfter(JoinPoint joinPoint) { System.out.println("After executing " + joinPoint.getSignature().getName() + " method"); } } ``` 在上面的示例中,我们定义了两个切点(Before和After),它们分别在方法执行前和执行后调用。 2. 定义切点表达式 切点表达式是AOP框架中的另一个核心组件,它决定了哪些方法会被切入。以下是一个示例切点表达式: ``` execution(* com.example.*.*(..)) ``` 这个表达式表示匹配com.example包下的所有类和方法。 3. 实现切面逻辑 切面逻辑是切面类中的具体实现,它定义了在切点处要执行的代码。以下是一个示例切面逻辑: ``` public void logBefore(JoinPoint joinPoint) { System.out.println("Before executing " + joinPoint.getSignature().getName() + " method"); } ``` 在这个示例中,我们简单地打印了一条日志。 4. 实现切面调用 切面调用是AOP框架中最重要的组件之一,它负责在切点处调用切面逻辑。以下是一个示例切面调用: ``` List<Aspect> aspects = getAspects(); // 获取所有切面 for (Aspect aspect : aspects) { if (aspect.matches(joinPoint)) { // 如果切面匹配当前方法,则调用其逻辑 aspect.invoke(joinPoint); } } ``` 在这个示例中,我们遍历所有切面并检查它们是否匹配当前方法。如果匹配,则调用切面逻辑。 5. 整合切面和切点表达式 最后,我们需要将切面和切点表达式整合到一起。以下是一个示例整合代码: ``` List<Aspect> aspects = getAspects(); // 获取所有切面 for (Aspect aspect : aspects) { Pointcut pointcut = aspect.getPointcut(); // 获取切点表达式 if (pointcut.matches(joinPoint)) { // 如果切面匹配当前方法,则调用其逻辑 aspect.invoke(joinPoint); } } ``` 在这个示例中,我们获取了切面的切点表达式,并使用matches方法检查其是否匹配当前方法。如果匹配,则调用切面逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值