文章目录
0.前言
1.aop概述
1.1.aop初理解
要理解切面编程,就需要先理解什么是切面。
用刀把一个西瓜分成两瓣,切开的切口就是切面
炒菜,锅与炉子共同来完成炒菜,锅与炉子就是切面
web层级设计中,web层->网关层->服务层->数据层,每一层之间也是一个切面。编程中,对象与对象之间,方法与方法之间,模块与模块之间都是一个个切面。
1.2.aop解决的问题
eg:访问接口前,需要先判断该接口是否需要用户登录,最笨的方法是
这样处理的弊端在于:有几个接口,就有几个完全相同的代码
因此作出改进:提出一个公共方法,每个接口都调用这个方法
这样处理仍有弊端:每个接口都要写一行调用的代码
因此便有了切面的概念:将方法(增强)注入到接口调用前的位置(切点)
2.aop的基本概念
2.1.概念
- 切面(Aspect):一个类,简单地说就是连接点与增强的组合
- 连接点(Joint point):所有可织入增强的点
- 切点(Pointcut):需要织入增强的特定连接点
- 增强(Advice):一个方法,代码执行到切点位置时,执行增强
- 目标对象(Target):被织入增强的这个对象
- 织入(Weaving):理解为连接、插入
据此,便有结论:
-
切面是一个类
-
增强是一个方法
-
连接点是可织入增强的点
-
每个方法有多个连接点(前、后、异常时等)
-
确定要织入增强的连接点被称为切点
2.2.比喻理解
从前有一个叫爪哇的小县城, 在一个月黑风高的晚上发生了命案。
老王恰好发现了凶手行凶的过程, 但是并没有看清凶手的面目, 只知道凶手是个男性, 身高约七尺五寸。
爪哇县的县令根据老王的描述, 对守门的士兵下命令说: 凡是发现有身高七尺五寸的男性, 都要抓起来审问。士兵当然不敢违背县令的命令, 只好把进出城的所有符合条件的人都抓了起来。
1) 连接点 - Joint point:爪哇县所有的百姓都可以是连接点
2) 切点 - PointCut:身高七尺五寸的爪哇县男性
3) 增强 - Advice:抓起来审问
Joint point
:爪哇的小县城里的百姓: 因为根据定义,Joint point
是所有可能被织入Advice
的候选的点, 在 Spring AOP中, 则可以认为所有方法执行点都是Joint point
。而在我们上面的例子中, 命案发生在小县城中, 按理说在此县城中的所有人都有可能是嫌疑人。
Pointcut
:男性, 身高约七尺五寸:我们知道, 所有的方法(Joint point
) 都可以织入Advice
, 但是我们并不希望在所有方法上都织入Advice
, 而Pointcut
的作用就是提供一组规则来匹配Joint point
, 给满足规则的Joint point
添加Advice
。同理, 对于县令来说, 他再昏庸, 也知道不能把县城中的所有百姓都抓起来审问, 而是根据凶手是个男性, 身高约七尺五寸, 把符合条件的人抓起来. 在这里 凶手是个男性, 身高约七尺五寸 就是一个修饰谓语, 它限定了凶手的范围, 满足此修饰规则的百姓都是嫌疑人, 都需要抓起来审问.
Advice
:抓过来审问,Advice
是一个动作, 即一段 Java 代码, 这段 Java 代码是作用于Pointcut
所限定的那些Joint point
上的. 同理, 对比到我们的例子中, 抓过来审问 这个动作就是对作用于那些满足“男性, 身高约七尺五寸”的爪哇县城里的百姓。
Aspect
:Aspect
是Point cut
与Advice
的组合, 因此在这里我们就可以类比: “根据老王的线索, 凡是发现有身高七尺五寸的男性, 都要抓过来审问” 这一整个动作可以被认为是一个Aspect
。
3.aop实现
aop常用于实现接口计时、输出日志等功能
下例以输出日志为例,用注解的方式实现aop
3.1.添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
3.2.创建包与类
- 包名:aop
- 类名:xxxAspect
- 加上@Aspect注解
- 加上@Component注解
3.3.编写增强(方法)
注意:这个Aspect中的返回值,将用于替换掉原方法的返回值!
eg:执行方法A时运用了AOP:
- 如果在Aspect中,程序被正确执行,方法A的返回值就被替换成了pjp.preceed()
也就是原来方法的返回值
- 如果在Asprct中,程序出现异常进入了catch,方法A的返回值就被替换成了null
3.3.1.exectution表达式
这里并不是正则表达式,"*"代表任意。针对以下execution表达式,有
execution(* com.eshang.aop.learning.controller..*.*(..))
符号 | 含义 |
---|---|
exection() | 表达式主体 |
第一个"*" | 返回值类型任意 |
“com.eshang.aop.learning.controller” | 切点所处的包名 |
第一个"…" | 表示controller包和其下任意子包 |
第二个"*" | 表示任意类名 |
第三个"*" | 表示任意方法名 |
括号里的"…" | 表示任意参数类型 |
AspectJ类型匹配的通配符:
*:匹配任何数量字符;
…:匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
+:匹配指定类型的子类型;仅能作为后缀放在类型模式后边。
3.3.2.输入参数
将ProceedingJoinPoint作为参数传入,调用以下方法,表示切点处代码放行
//代码放行
Object result = pjp.proceed();
按照规范,应将result作为该增强(Aspect)方法的返回值。