AspectJ 使用及原理

AspectJ 使用及原理一.简介二.原理三.使用(一)基本概念1.连接点(JoinPoint)2.切点(PointCut)3.插入逻辑(Advice)4.切面(Aspect)(二)类型匹配表达式1.注解2.修饰符3.返回值4.类5.方法名6.方法参数7.组合使用(三)切入点组合表达式1.call/execution2.this3.target4.within5.args6.注解支持7.组合使用8...
摘要由CSDN通过智能技术生成

一.简介

Aspect Oriented Programming(AOP)面向切面编程是目前比较流行的一种编程方式,切面是指从不同的角度来看待同一个事物,比如我们做一个Android app需求时候,是从业务逻辑角度考虑的,需要实现一个Activity,实现一个model,实现一个View,再在Activity里完成对View和model控制等等;再比如我们需要对整个app的所有Activity做一些性能监控,这时候就需要从整个项目的角度来考虑,需要实现的就是统一对每个Activity或基类做处理,而不是某个业务的Activity了。

AOP就是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种编程思想,也就是不需要侵入代码(比如修改基类等)就可以实现功能模块,而AspectJ就是该思想的一种具体实现方式,它是一个面向切面的框架,它扩展了Java语言。

二.原理

AspectJ定义了AOP语法,所以它有一个专门的编译器用来生成遵守Java字节编码规范的Class文件。

AspectJ定义了一组注解,对应着一组概念,还有一套匹配表达式,我们通过书写匹配表达式,告知AspectJ我们想在哪些地方添加代码,然后再通过不同的注解,决定我们想以什么样的方式在源代码处做什么样的事,最后在编译时,AspectJ的编译器就会按照我们的想法,在源代码里注入新的代码,也可以理解为AspectJ hook住了编译过程,添加了一些代码。

先举个简单的小例子来验证下AspectJ的实现效果:

假如我们想要在所有的Activity的onCreate执行时,先输出一个log,那么我们定义自己的切面

@Aspect
class InheritAspect {
   
    private companion object {
   
        private const val TAG = "InheritAspect"
        private const val ON_CREATE_EXECUTION = "execution(void *..*Activity.onCreate(..))"
    }
 
    @Pointcut(ON_CREATE_EXECUTION)
    fun onCreateExecution() {
   
    }

    @Before("onCreateExecution()")
    fun beforeOnCreateExecution(joinPoint: JoinPoint) {
   
        Log.i(TAG,"onCreate start")
    }
}

代码先不用管,意思就是定义了一个切面,拦截的是所有Activity的onCreate方法的执行,并且在执行时,输出一个log

下面我们来看看,运行后其中一个Activity的文件,反编译过后的结果:

//源代码
protected void onCreate(@Nullable Bundle var1) {
   
   super.onCreate(var1);
}
//运行后
protected void onCreate(@Nullable Bundle var1) {
   
   JoinPoint var2 = Factory.makeJP(ajc$tjp_7, this, this, var1);
   //拿到InheritAspect的单例对象
   InheritAspect.aspectOf().beforeOnCreateExecution(var2);
   super.onCreate(var1);
}

我们可以看到,在这个Activity的onCreate方法中,先执行的就是InheritAspect类的beforeOnCreateExecution方法(JoinPoint对象就是包装了一些切点的信息),该方法就是我们上面定义的那个方法,输出了log,可见,AspectJ的编译器按照我们的想法,在源码上添加了代码。

知道了大概原理,我们就来看看怎么使用吧!

三.使用

(一)基本概念

1.连接点(JoinPoint)

连接点是程序中可以插入代码的地方,比如调用一个方法、一个方法执行中、调用一个构造器、一个构造器执行中等等,被AspectJ支持的连接点如下:
在这里插入图片描述

2.切点(PointCut)

切点其实就是想要在哪些地方插入一段代码,也就是一组连接点集合的逻辑组合关系,比如一个切点可以定义为:调用A类的a方法时||调用B类的b方法时;这样当调用A类的a方法这个连接点或者调用B类的b方法这个连接点时都会被该切点切入,从而插入代码

3.插入逻辑(Advice)

上面说的是定义的切点,即静态点,有了静态点后,就需要插入代码了,插入代码的方式AspectJ也定义了几种:

  • Before

    在连接点之前插入代码

  • After

    在连接点之后插入代码

  • Around

    代理连接点,可以自定义是否执行连接点或返回何种结果等

4.切面(Aspect)

切面就是包装了连接点、切点、插入逻辑的单一模块,也是AspectJ扫描的单元,一个切面定义了一组AOP功能

以上是AspectJ的基本概念,下面带着这些概念,进入到具体的使用学习中吧!

(二)类型匹配表达式

对于AOP来说,最重要的就是要准确的找到想要切入的点了,AspectJ提供了一套匹配表达式来完成,主要的结构如下({}为可选项):

{注解}{修饰符}<返回值>{类}<方法名><方法参数>

下面我们来结合例子来学习,如何使用匹配表达式定位到具体方法

1.注解

此处的注解为标注在方法上的注解

@java.lang.Deprecated * *(..)

表示标有@java.lang.Deprecated注解的所有方法

2.修饰符

public * *(..)

表示所有public的方法,这个不用多说

3.返回值

* *(..)

*表示任意类型,所以该表达式表示任何方法

void *(..)

表示返回值为void的所有方法

java.lang.String *(..)

表示返会String类型的所有方法

java.lang.String+ *(..)

+表示子类,所以该表达式表示返回String及其子类类型的所有方法

java.lang.* *(..)

表示返回java.lang包下所有类型的方法

java.lang.String* *(..)

*也可以作为任意字符个数的匹配(前缀后缀),该表达式表示返回java.lang包下,以String为前缀的所有类型,的所有方法

java..* *(..)

…表示的是当前包及其任意子包下(包括子包的子包等),该表达式表示返回java包及其底下所有包下的类型,的所有方法

(@java.lang.Deprecated *) *(..)

此处注解声明在*上(括号包住),表示该返回值的类型上有@java.lang.Deprecated注解的所有方法

4.类

类的匹配规则大多与返回值类似

* com..*Activity+.*(..)

表示com包及其子包下,以Activity为后缀的所有类及其子类,的所有方法,此处+、*与…和返回值处一样

* (@java.lang.Deprecated *).*(..)

表示所有标有@java.lang.Deprecated注解的类的所有方法

5.方法名

方法名就相对简单了

  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AspectJ是一种基于Java语言的面向切面编程(AOP)的扩展。它通过在编译期间将切面代码织入到目标代码中,实现了对横切关注点的模块化和重用。 AspectJ的实现原理主要包括以下几个步骤: 1. 编译器扩展:AspectJ通过扩展Java编译器,添加了对切面语法的支持。在编译Java源代码时,AspectJ编译器会解析切面文件中的切点和通知,并将其转换为字节码文件。 2. 切点匹配:AspectJ使用切点表达式来定义切点,切点表达式可以根据方法的签名、注解、访问修饰符等条件来匹配目标代码中的连接点。AspectJ编译器会根据切点表达式在目标代码中找到匹配的连接点。 3. 通知织入:一旦找到匹配的连接点,AspectJ会将切面中定义的通知代码织入到目标代码中。通知可以分为前置通知、后置通知、环绕通知等,它们会在目标代码执行前、后或者替代目标代码执行。 4. 字节码增强:AspectJ通过修改目标代码的字节码来实现通知的织入。它会在目标代码中插入切面代码,并调整字节码中的跳转指令,以确保通知的正确执行顺序。 5. 运行时支持:AspectJ还提供了运行时的支持,包括切面实例的创建和管理、连接点的动态绑定、通知的执行等。在程序运行时,AspectJ会根据切面的定义和连接点的匹配情况来决定是否执行通知。 总的来说,AspectJ通过编译器扩展和字节码增强的方式,将切面代码织入到目标代码中,实现了对横切关注点的模块化和重用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值