Spring AOP 基础概述
Spring AOP 基础概述
文章目录
前言
本系列主要讨论 Spring AOP 相关的内容,和大多数实战使用的文章不同,本系列主要关注在设计和源码层面;分为 4 篇进行发布,分别是:
- Spring AOP 基础概述
- Spring AOP 的设计与实现
- Spring AOP 创建 AopProxy 代理对象原理分析
- Spring AOP 拦截器调用的实现
本章主要是介绍一些 AOP 的基础概念。
1.AOP是什么?
AOP:Aspect-Oriented Programming(面向切面编程)
百度百科
在软件业,AOP 为 Aspect Oriented Programming 的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
2.AOP 用来解决什么问题?
代码复用,公共函数抽取,简化开发,业务之间的解耦;最典型的例子就是日志功能,因为日志功能往往横跨系统中的每个业务模块,使用 AOP 可以很好的将日志功能抽离出来。
3.AOP 技术有哪些?
- AspectJ:源代码和字节码解包的编织器,用户需要使用不同于 Java 的新语言
- AspectWerkz:AOP 框架,使用字节码动态编织器和 XML 配置
- JBoss-AOP:基于拦截器和元数据的 AOP 框架,运行在 JBoss 应用服务器上,以及 AOP 中用到的一些相关技术实现
- BCEL(Byte-Code Engineering Library):Java 字节码操作类库
- Javassist:Java 字节码操作类库,JBoss 的一个子项目
4.AOP 体系结构图
AOP 体系结构大致分为由高到低、从使用到实现的三个层次
- 语言和开发环境
- 面向方面系统
- 底层编织(组织)实现模块
原文是
编织
,但是听起来总是感觉很奇怪,不像互联网词汇,后面的文章中可以理解为组织、整合。
4.1 第一层:语言和开发环境
- 基础(base):待增强对象或者说目标对象
- 切面(aspect):通常包含对于基础的增强应用
- 配置(configuration):可以看成是一种编织,通过在 AOP 体系中提供这个配置环境,把基础和切面结合起来,从而完成切面对目标对象的编织实现
在 Spring AOP 实现中,使用 Java 来实现增强对象与切面增强应用,并为这两者集合提供了配置环境。
4.2 第二层:面向方面系统
第二层是为语言和开发环境提供支持的,主要包括配置和编织实现两部分内容。例如配置逻辑和编织逻辑实现本身,以及对这些实现进行抽象的一些高层 API 封装。
4.3 第三层:具体实现
最底层是编织的具体实现模块,具体实现方法比反射、程序预处理。拦截器框架、类装载框架、元数据处理等。在 Spring AOP 中,使用的是 Java 语言特性,如 Java Proxy 代理类、拦截器技术来完成 AOP 编织的实现。
5.Advice 通知
Advice(通知)定义在连接点做什么,为切面增强提供接口。在 Spring AOP 中,它主要描述 Spring AOP 环绕方法调用而诸如的切面行为。
Advice 是 AOP 联盟定义的一个接口,具体的接口定义在 org.aopalliance.aop.Advice 中。在 Spring 中使用了这个统一接口,做了一些细化和扩展,比如下面的三个接口
- org.springframework.aop.BeforeAdvice 前置通知
- org.springframework.aop.AfterAdvice 后置通知
- org.springframework.aop.ThrowsAdvice 异常通知
5.1 前置通知
在 Spring 定义了为待增强的目标方法设置的前置增强接口 MethodBeforeAdvice ,代码如下:
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method method, Object[] args, @Nullable Object target) throws Throwable;
}
在目标方法执行之前,进行调用,起到增强的效果。
参数:
- Method method,目标对象方法的反射对象
- Object[] args,这个对象数组中包含目标方法的输入参数
- Object target,方法调用的目标
5.2 后置通知
AfterReturningAdvice 是一个比较常见的 AfterAdvice 的接口
public interface AfterReturningAdvice extends AfterAdvice {
void afterReturning(@Nullable Object returnValue, Method method, Object[] args, @Nullable Object target) throws Throwable;
}
和 5.1 中的前置通知不一样,这个是在目标方法成功调用之后返回结果后调用,实现切面增强。
如果有一段相同逻辑的代码,既需要在方法前调用,也需要在返回之后调用,那么 AOP 的作用就体现出来了,我们将这段逻辑代码封装成一个功能的方法,然后只需要在 前置通知 和 后置通知 两个地方调用这个方法即可。
5.3 异常通知
对于 ThrowsAdvice,并没有指定需要实现的接口方法,它在抛出异常时被回调,这个回调是 AOP 使用反射机制来完成的。
6.Pointcut 切点
Pointcut(切点)决定 Advice 通知应该作用于哪个连接点,也就是说通过 Pointcut 来定义需要增强的方法集合,这些集合的选取可以按照一定的规则来完成。在这种情况下,Pointcut 通常意味着表示方法,例如,这些需要增强的地方可以由某个正则表达式来进行标识,或者根据某个方法名进行匹配等等。
- org.springframework.aop.Pointcut 源码如下:
public interface Pointcut {
/**
* Return the ClassFilter for this pointcut.
* @return the ClassFilter (never {@code null})
*/
ClassFilter getClassFilter();
/**
* Return the MethodMatcher for this pointcut.
* @return the MethodMatcher (never {@code null})
*/
MethodMatcher getMethodMatcher();
/**
* Canonical Pointcut instance that always matches.
*/
Pointcut TRUE = TruePointcut.INSTANCE;
}
在接口定义中可以看到,需要返回一个 MethodMatcher 对象。从这个命名就可以看出,这个方法是用来判断是否需要对当前方法调用进行增强,或者是否需要对当前方法使用配置好的 Advice 通知。
具体实现:org.springframework.aop.support.JdkRegexpMethodPointcut#matches
@Override
protected boolean matches(String pattern, int patternIndex) {
Matcher matcher = this.compiledPatterns[patternIndex].matcher(pattern);
return matcher.matches();
}
这个 matches 方法就是使用正则表达式来对方法名称进行匹配,本章只是先简单提一下。
7.Advisor 通知器
完成对目标方法的切面增强设计(Advice)和关注点的设计(Pointcut)以后,需要一个对象将它们结合起来,完成这个作用的就是 Advisor(通知器)。
通过 Advisor 可以定义应该使用哪个通知(Advice)并在哪个关注点(Pointcut)使用它,也就是说通过 Advisor 把 Advice 和 Pointcut 结合起来,这个结合为使用 IoC 容器配置 AOP 应用提供了便利。在 Spring 中有一个默认的实现,代码如下:
- org.springframework.aop.support.DefaultPointcutAdvisor
public class DefaultPointcutAdvisor extends AbstractGenericPointcutAdvisor implements Serializable {
private Pointcut pointcut = Pointcut.TRUE;
public DefaultPointcutAdvisor() {
}
public DefaultPointcutAdvisor(Advice advice) {
this(Pointcut.TRUE, advice);
}
public DefaultPointcutAdvisor(Pointcut pointcut, Advice advice) {
this.pointcut = pointcut;
setAdvice(advice);
}
public void setPointcut(@Nullable Pointcut pointcut) {
this.pointcut = (pointcut != null ? pointcut : Pointcut.TRUE);
}
@Override
public Pointcut getPointcut() {
return this.pointcut;
}
@Override
public String toString() {
return getClass().getName() + ": pointcut [" + getPointcut() + "]; advice [" + getAdvice() + "]";
}
}
private Pointcut pointcut = Pointcut.TRUE;
Pointcut 默认设置是一个单例的实现
代码如下:
final class TruePointcut implements Pointcut, Serializable {
public static final TruePointcut INSTANCE = new TruePointcut();
/**
* Enforce Singleton pattern.
*/
private TruePointcut() {
}
@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}
@Override
public MethodMatcher getMethodMatcher() {
return MethodMatcher.TRUE;
}
private Object readResolve() {
return INSTANCE;
}
@Override
public String toString() {
return "Pointcut.TRUE";
}
}
同样的 TruePointcut 中的 MethodMatcher.TRUE 也是一个单例的实现,其中 matches 方法默认返回 true。也就是说对任何方法名的匹配都会返回成功。
8.参考
- 《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》- 计文柯
本文地址:https://blog.csdn.net/xiewenfeng520/article/details/107321596