SpringBoot:切面AOP权限校验:实例演示与注解全解( 三 )

重启项目 , 继续测试 , 构造两个参数都异常的情况:
SpringBoot:切面AOP权限校验:实例演示与注解全解文章插图
响应结果 , 表面第二个切面类执行顺序更靠前:
SpringBoot:切面AOP权限校验:实例演示与注解全解文章插图
3 AOP相关注解上面的案例中 , 用到了诸多注解 , 下面针对这些注解进行详解 。
3.1 @Pointcut@Pointcut 注解 , 用来定义一个切面 , 即上文中所关注的某件事情的入口 , 切入点定义了事件触发时机 。
@Aspect@Componentpublic class LogAspectHandler {/*** 定义一个切面 , 拦截 com.itcodai.course09.controller 包和子包下的所有方法*/@Pointcut("execution(* com.mutest.controller..*.*(..))")public void pointCut() {}}@Pointcut 注解指定一个切面 , 定义需要拦截的东西 , 这里介绍两个常用的表达式:一个是使用 execution() , 另一个是使用 annotation() 。
execution表达式:
以 execution(* * com.mutest.controller..*.*(..))) 表达式为例:

  • 第一个 * 号的位置:表示返回值类型 , * 表示所有类型 。
  • 包名:表示需要拦截的包名 , 后面的两个句点表示当前包和当前包的所有子包 , 在本例中指 com.mutest.controller包、子包下所有类的方法 。
  • 第二个 * 号的位置:表示类名 , * 表示所有类 。
  • (..):这个星号表示方法名 , 表示所有的方法 , 后面括弧里面表示方法的参数 , 两个句点表示任何参数 。
annotation() 表达式:
annotation() 方式是针对某个注解来定义切面 , 比如我们对具有 @PostMapping 注解的方法做切面 , 可以如下定义切面:
@Pointcut("@annotation(org.springframework.web.bind.annotation.PostMapping)")public void annotationPointcut() {}然后使用该切面的话 , 就会切入注解是 @PostMapping 的所有方法 。 这种方式很适合处理 @GetMapping、@PostMapping、@DeleteMapping不同注解有各种特定处理逻辑的场景 。
还有就是如上面案例所示 , 针对自定义注解来定义切面 。
@Pointcut("@annotation(com.example.demo.PermissionsAnnotation)")private void permissionCheck() {}3.2 @Around@Around注解用于修饰Around增强处理 , Around增强处理非常强大 , 表现在:
  1. @Around可以自由选择增强动作与目标方法的执行顺序 , 也就是说可以在增强动作前后 , 甚至过程中执行目标方法 。 这个特性的实现在于 , 调用ProceedingJoinPoint参数的procedd()方法才会执行目标方法 。
  2. @Around可以改变执行目标方法的参数值 , 也可以改变执行目标方法之后的返回值 。
Around增强处理有以下特点:
  1. 当定义一个Around增强处理方法时 , 该方法的第一个形参必须是 ProceedingJoinPoint 类型(至少一个形参) 。 在增强处理方法体内 , 调用ProceedingJoinPoint的proceed方法才会执行目标方法:这就是@Around增强处理可以完全控制目标方法执行时机、如何执行的关键;如果程序没有调用ProceedingJoinPoint的proceed方法 , 则目标方法不会执行 。
  2. 调用ProceedingJoinPoint的proceed方法时 , 还可以传入一个Object[ ]对象 , 该数组中的值将被传入目标方法作为实参——这就是Around增强处理方法可以改变目标方法参数值的关键 。 这就是如果传入的Object[ ]数组长度与目标方法所需要的参数个数不相等 , 或者Object[ ]数组元素与目标方法所需参数的类型不匹配 , 程序就会出现异常 。
@Around功能虽然强大 , 但通常需要在线程安全的环境下使用 。 因此 , 如果使用普通的Before、AfterReturning就能解决的问题 , 就没有必要使用Around了 。 如果需要目标方法执行之前和之后共享某种状态数据 , 则应该考虑使用Around 。 尤其是需要使用增强处理阻止目标的执行 , 或需要改变目标方法的返回值时 , 则只能使用Around增强处理了 。
下面 , 在前面例子上做一些改造 , 来观察@Around的特点 。
自定义注解类不变 。 首先 , 定义接口类:
package com.example.demo;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import org.springframework.web.bind.annotation.*;@RestController@RequestMapping(value = "http://kandian.youth.cn/permission")public class TestController {@RequestMapping(value = "http://kandian.youth.cn/check", method = RequestMethod.POST)@PermissionsAnnotation()public JSONObject getGroupList(@RequestBody JSONObject request) {return JSON.parseObject("{\"message\":\"SUCCESS\",\"code\":200,\"data\":" + request + "}");}}唯一切面类(前面案例有两个切面类 , 这里只需保留一个即可):