spring源码系列-AOP 联盟 AOP 通用接口定义
使用
- 使用其实不用多说,切面编程是一个几乎没有侵入性的编程方式。常见的是对日志的记录(进入了哪个方法,入参记录等等)
- 常见的切如方式为注解,和路径确定方法。没有本质的区别。注解的用法相对来说使用频率会高一些。
源码基本接口
AOP 通知部分
advice通知接口
由图可以看出来。这个接口没有继承任何接口,且方法为空。是一个定义接口:可以实现任何类型的通知。
定义异常类
这个类实现的 RuntimeException
是jdk的运行过程中异常类。
这里要说一下这俩的异常类的区别了:
Exception:非运行时异常,在项目运行之前必须处理掉。一般由程序员 try…catch掉。
RuntimeException:运行时异常,在项目运行之后出错则直接终止运行,异常由JVM虚拟机处理。
在接口的逻辑判断出现异常时,可能会影响后面的代码。或者说绝不容忍(允许)该代码块出错,那么我们就用RuntimeException,但是我们又不能因为系统挂掉,只能在后台抛出异常而不给前端返回友好的提示吧,至少给前端返回出现异常的原因吧。因此接口的自定义异常作用就体现了出来。
这里继承这个异常的,用的super
使用父类的方法处理。最终的会调用到Throwable
的对应的构造方法。处理,弹出栈。
AOP 反射拦截抽象部分(懒的同学直接看下图就行)
这个部分的所有介绍关系的关系图:
方法关系结构图:
通用拦截器 Interceptor接口
这个接口代表一个通用的拦截器。 通用拦截器可以拦截基本程序中发生的运行时事件。 这些事件由(具体化)连接点实现。
运行时连接点可以是调用、字段访问、异常… 该接口不直接使用。 使用子接口拦截特定事件。
ConstructorInterceptor构造器
拦截新对象的构造。 用户应该实现construct(ConstructorInvocation)方法来修改原始行为。
此接口只有一个接口:
construct(ConstructorInvocation invocation)
实现此方法以在构建新对象之前和之后执行额外的处理。 礼貌的实现当然希望调用Joinpoint.proceed() 。
参数: 调用——构造连接点 返回: 新创建的对象,也是调用Joinpoint.proceed() ; 可能会被拦截器取代 抛出:
Throwable - 如果拦截器或目标对象抛出异常
Joinpoint 接口
此接口表示通用运行时连接点(在 AOP 术语中)。 运行时连接点是,在一个静态的连接点时发生的事件(即,在一个程序中的位置)。
例如,调用是方法上的运行时连接点(静态连接点)。 可以使用getStaticPart()方法一般检索给定连接点的静态部分。
在拦截框架的上下文中,运行时连接点是对可访问对象(方法、构造函数、字段)的访问的具体化,即连接点的静态部分。
它被传递给安装在静态连接点上的拦截器。
简单来理解就是定义切入点的一系列方法!
里面有三个定义方法proceed()
getThis()
getStaticPart()
。
proceed() 方法
继续处理链中的下一个拦截器。 此方法的实现和语义取决于实际的连接点类型(请参阅子接口,具体的返回值还是得看具体的实现方法)。
getThis()方法
返回保存当前连接点静态部分的对象。 例如,调用的目标对象。
返回值 对象(如果可访问的对象是静态的,则可以为 null
getStaticPart() 方法
返回此连接点的静态部分。 静态部分是一个可访问的对象,其上安装了一系列拦截器。
Invocation调用接口
此接口代表程序中的调用。 调用是一个连接点,可以被拦截器拦截
这个调用接口继承了前一个Joinpoint
接口,在此基础上添加了一个getArguments()
方法。
getArguments()方法
将参数作为数组对象获取。 可以更改此数组中的元素值以更改参数。
返回: 调用的参数
ConstructorInvocation构造调用
对构造函数的调用的描述,在构造函数调用时提供给拦截器。 构造函数调用是一个连接点,可以被构造函数拦截器拦截。
也可以看看: ConstructorInterceptor
该接口继承了Invocation接口
相当于一共定义了5个方法。
getArguments()
proceed()
getThis()
getStaticPart()
。
出来上面介绍的四个方法,该接口自己定义了一个方法:
Constructor<?> getConstructor()
获取被调用的构造函数。 此方法是Joinpoint.getStaticPart()方法的友好实现(结果相同)。
返回: 被调用的构造函数
MethodInterceptor 拦截器方法定义接口
在通往目标的途中拦截接口上的调用。 它们嵌套在目标的“顶部”。
用户应该实现invoke(MethodInvocation)方法来修改原始行为。
例如,以下类实现了一个跟踪拦截器(跟踪对被拦截方法的所有调用)
首先看一下继承图解里面的FunctionalInterface 注解。
用于指示接口类型声明旨在成为 Java 语言规范定义的功能接口的信息性注释类型。 从概念上讲,函数式接口只有一个抽象方法。
由于默认方法具有实现,因此它们不是抽象的。
如果接口声明了一个覆盖java.lang.Object的公共方法之一的抽象方法,这也不会计入接口的抽象方法计数,因为接口的任何实现都将具有来自java.lang.Object或其他地方的实现。
请注意,可以使用 lambda 表达式、方法引用或构造函数引用创建函数式接口的实例。
如果使用此注释类型对类型进行注释,则编译器需要生成错误消息,除非: 该类型是接口类型,而不是注释类型、枚举或类。
带注释的类型满足功能接口的要求。
但是,无论接口声明中是否存在FunctionalInterface注释,编译器都会将满足函数式接口定义的任何接口视为函数式接口。
除了继承的方法以外,此接口还申明了一个方法:
Object invoke(@Nonnull MethodInvocation invocation)
实现此方法以在调用之前和之后执行额外的处理。 礼貌的实现当然希望调用Joinpoint.proceed() 。
参数: invocation – 方法调用连接点 返回: 调用Joinpoint.proceed() ; 可能被拦截器拦截 抛出:
Throwable - 如果拦截器或目标对象抛出异常
MethodInvocation 调用方法接口定义
方法调用的描述,在方法调用时提供给拦截器。 方法调用是一个连接点,可以被方法拦截器拦截。 也可以看看: MethodInterceptor
除了继承的方法以外,此处还声明了一个方法:
Method getMethod()
获取被调用的方法。 此方法是Joinpoint.getStaticPart()方法的友好实现(结果相同)。