AOP能干什么?
- AOP能干什么?
- 预备知识
- Before Advice
- After Advice
- Around Advice
- AOP能干啥呢
- 处理参数值
- 处理输出结果
- 总结
AOP能干什么?
我们在之前的博客中已经提出了一个例子,可以通过AOP来实现权限的一个认证,详情可以参考这篇博客
AOP是什么
总所周知哈,AOP可以在不改变原代码的情况下完成一些我们意想不到操作,那么到底可以用来干什么呢?咱们一起来看一看
预备知识
首先,咱们要先了解一些小知识点,首先什么是Advice?
例如,我们设计了一个验证码校对接口,因为我们并不需要区别大小写,所以我们要把输入的字母全都调整为大写,但是我们并不想在接口内部对字母进项大写操作,因此我们在接口前建立一个切面,把所有的字母都调整为大写,把字母调整为大写的操作就是Advice。
Advice的类别有以下几类,为了方便理解,我们以接口为例介绍Advice的类别。
Before Advice
可以理解为进入接口之前的操作,也就是刚刚我们提到的字母进入接口之前,先用我们的Advice把它调成大写,举个栗子
Aspect
Aspect就是point cut 与 Advice的组合
package com.xiaow.springsecuriydemo.aop.advice;import com.xiaow.springsecuriydemo.entity.Admin;
import com.xiaow.springsecuriydemo.entity.Person;
import com.xiaow.springsecuriydemo.service.AdminService;
import com.xiaow.springsecuriydemo.service.PersonService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;import java.lang.reflect.Array;
import java.util.List;@Aspect
@Component
public class TestAdvice {//Pointcut@Pointcut("@annotation(com.xiaow.springsecuriydemo.aop.annotation.TestAnnotation)")public void TestPointCut() {}//Advice@Before(value = "TestPointCut()")public void before(JoinPoint joinPoint) throws IllegalAccessException, NoSuchFieldException {System.out.println("Advice");}}
Controller
@GetMapping("testAOP")@TestAnnotationpublic Result testAOP(@RequestParam(required = false) String info) {System.out.println("接口处理");return Result.succ(info);}
调用接口之后可以发现,先进行的Before Advice然后执行接口内的操作
After Advice
接口执行完毕之后执行的Advice,无论接口内操作正常结束还是抛出异常,都会执行的内容
把注解改一下就可以,由Before改为了After
@After(value = "TestPointCut()")public void before(JoinPoint joinPoint) throws IllegalAccessException, NoSuchFieldException {System.out.println("Advice");}
看下结果
确实Advice是在接口之后执行的,那么咱们看看有异常了还能执行吗
改下接口,经典的1/0
@GetMapping("testAOP")@TestAnnotationpublic Result testAOP(@RequestParam(required = false) String info) {System.out.println("接口处理");int a=1/0;return Result.succ(info);}
看下结果
虽然一堆异常,但很明显还是执行了
Around Advice
这个我认为是最自由的Advice了。Around,顾名思义,环绕的意思,就是说进入接口前和出接口后,都可以操作,那么我们想要修改参数值,返回值之类的就很方便了。这里举个例子。
修改下Advice
@Around(value = "TestPointCut()")public void before(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before");Object[] args = joinPoint.getArgs();Object proceed = joinPoint.proceed(args);System.out.println("After");}
输出结果如下
可以注意到,此时若是接口中出现异常,并不能返回输出After。
那怎么次啊能无视异常,直接输出After呢?
这时候,你就突然想到了,这里不进行下面操作了是因为我们把异常抛出去了,那我们直接不抛不就完事了
@Around(value = "TestPointCut()")public void before(ProceedingJoinPoint joinPoint) throws Throwable {System.out.println("Before");try {Object[] args = joinPoint.getArgs();Object proceed = joinPoint.proceed(args);}catch (Exception e){e.printStackTrace();}System.out.println("After");}
输出结果如下,这不就可以了
另外,还有两类,这里博主就不仔细讲了,咱们主要是围绕着Around Advice进行处理,来看看这能有什么用吧
AOP能干啥呢
这里我们从输入参数和返回结果两方面去考虑哈。
例如说,我们在接收到一些参数值时,我们可能需要对其进行处理之后才能使用,并且每个接口都需要做这样的预处理,这时候每个接口都写相同的代码就太冗余了,那是不是可以用AOP进行处理呢,答案是可以的。
另外,我们在返回结果时,也需要对结果处理之后才能返回,同样所有接口都需要做这个操作,这个固定的操作同样也可以用AOP进行处理。
咱们举两个例子来看下怎么搞吧。
处理参数值
ok,还是刚才的例子哈。
假如哈,重点是假如哈。
博主来扮演一个极度自恋的人,即使听到别人说我丑,博主也会自动认为被人再夸博主帅
那我们怎么做呢,是不是把输入的丑字换成帅就可以了,然后帅的话就什么都不管了
那看看咋弄哈
@GetMapping("testAOP")@TestAnnotationpublic Result testAOP(@RequestParam(required = false) String info) {return Result.succ(info);}
Controller不需要变,就改Aspect就可以,这就是AOP的魅力!
注意哈
Object proceed = joinPoint.proceed(args);
joinPoint.proceed完全可以认为是执行接口函数,也就是proceed就是接口输出的结果,args就是我们传递给接口的参数值,那么就很好改了,那咱们直接改下args就可以了,
@Around(value = "TestPointCut()")public Object before(ProceedingJoinPoint joinPoint) throws Throwable {Object proceed=null;System.out.println("Before");try {// 获取方法的参数值Object[] args = joinPoint.getArgs();String info = (String) args[0];// 修改传递的参数值args[0] = info.replaceAll("丑", "帅");// 传递修改的参数值给接口proceed = joinPoint.proceed(args);}catch (Exception e){e.printStackTrace();}System.out.println("After");return proceed;}
调用路径
http://localhost:8080/test/testAOP?info=太丑了
输出结果
很对!
处理输出结果
那么咱们怎么更改这个输出结果呢,和上面一样,改一下proceed就可以了,来看看咋改吧
@Around(value = "TestPointCut()")public Object before(ProceedingJoinPoint joinPoint) throws Throwable {Object proceed=null;System.out.println("Before");try {Object[] args = joinPoint.getArgs();proceed = joinPoint.proceed(args);}catch (Exception e){e.printStackTrace();}// 获取原来的结果Result result= (Result) proceed;// 能到原来结果返回的字符串String info = (String) result.getData();// 修改该字符串,然后设置给返回结果result.setData(info.replaceAll("丑", "帅"));System.out.println("After");return result;}
来看看结果,这就很对了
总结
上面只是开个玩笑,其实Around Advice有很多大用处。
例如,一个接口是基于参数值查询结果,但是并没有设置权限,会导致没有权限的用户传递参数之后获取到不应该让他看到的数据,此时就可以对参数值进行处理,滤除掉不应该被传递过来的参数。
另外,我们在数据库设置1或0表示一种状态,但是前端不能显示0和1啊,这时候就可以通过修改输出结果来给出详细的状态描述,也可以理解为一种字典翻译。
好了,今天的AOP就到这了,溜了溜了