springboot切面AOP简单使用

416 阅读1分钟

引入依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-aop</artifactId>
      <version>2.1.3.RELEASE</version>
    </dependency>

切入点

@RestController
@Params
public class JimDbController {

  @RequestMapping(value = "/aspect",method = {RequestMethod.GET})
  @SMSAndMailSender(smsContent = "橙xxxxx")
  public GatewayResult<Boolean> aspectJController(@RequestBody PowerQuery powerQuery) {
    return new GatewayResult<>().buildSuccess(powerQuery.getPowerName().equals("成功"));
  }
}  

自定义注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Order(1)
public @interface Params {
  String value() default "";
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Order(2)
public @interface SMSAndMailSender {
  String value() default "";
  String smsContent() default "";
  String mailContent() default "";
  boolean isActive() default true;
  String subject() default "";
}

正常执行

1.jpg

出现异常

2.jpg

增强切面类

@Aspect
@EnableAspectJAutoProxy
@Component
@Slf4j
@Order(2)
public class AdviceHandle {

  //环绕增强
  //环绕通知非常强大,可以决定目标方法是否执行,什么时候执行,执行时是否需要替换方法参数,执行完毕是否需要替换返回值。
  @Around("execution(* com.cool.controller.JimDbController.aspe*(..))")
  public Object process(ProceedingJoinPoint point) throws Throwable {
    Object[] args = point.getArgs();
    log.info("Around 参数:" + args.toString());
    Object proceed = point.proceed(args);
    String methodKey = point.toLongString();
    log.info("Around methodKey:" + methodKey);
    return proceed;
  }

  //标识一个前置增强方法, @within是针对类的注解
  @Before("@within(com.cool.domain.Params)")
  public void permissionCheck(JoinPoint point) {
    log.info("Before:" + point.getSignature().getName());
    log.info("Before:" + point.getTarget().toString());
  }

  //final增强,不管是抛出异常或者正常退出都会执行。
  @After(value = "@annotation(com.cool.domain.SMSAndMailSender) && args(powerQuery)")
  public void after(JoinPoint joinPoint, PowerQuery powerQuery) {
    log.info("After 参数:" +powerQuery);
  }

  // 后置增强, 方法正常退出时执行
  @AfterReturning(value = "execution(* com.cool.controller.JimDbController.aspe*(..))", returning = "returnValue")
  public void log(JoinPoint point, Object returnValue) {
    log.info("AfterReturning:" + Arrays.toString(point.getArgs()));
    log.info("AfterReturning:" + returnValue.toString());
  }

  //@annotation是针对方法的注解
  @AfterReturning(value = "@annotation(com.cool.domain.SMSAndMailSender)", returning = "re")
  public void afterReturn(JoinPoint join, Object re) {
    MethodSignature ms = (MethodSignature) join.getSignature();
    Method method = ms.getMethod();
    boolean active = method.getAnnotation(SMSAndMailSender.class).isActive();
    if (!active) {
      return;
    }
    String content = method.getAnnotation(SMSAndMailSender.class).smsContent();
    log.info("AfterReturning 注解信息:" + content);
    log.info("AfterReturning 返回值信息:" + re);
  }

  //异常抛出增强
  @AfterThrowing(value = "@within(org.springframework.web.bind.annotation.RestController)", throwing = "ex")
  public void afterThrow(JoinPoint join, Throwable ex) {
    MethodSignature signature = (MethodSignature) join.getSignature();
    Method method = signature.getMethod();
    String subject = method.getAnnotation(SMSAndMailSender.class).subject();
    log.info(subject);
    log.info("异常" + ex.getMessage());
  }

}

同一方法被多个切面拦截

类优先级通过注解@Order(数字)确定或者让切面类实现org.springframework.core.Ordered接口:实现该接口的int getOrder()方法,数字越小优先级越高。

优先级高的切面类里的增强处理的优先级总是比优先级低的切面类中的增强处理的优先级高。

在“进入”连接点时,最高优先级的增强处理将先被织入(eg.给定的两个不同切面类Before增强处理中,优先级高的那个会先执行);在“退出”连接点时,最高优先级的增强处理会最后被织入(eg.给定的两个不同切面类After增强处理中,优先级高的那个会后执行)。eg.优先级为1的切面类Bean1包含了@Before,优先级为2的切面类Bean2包含了@Around,虽然@Around优先级高于@Before,但由于Bean1的优先级高于Bean2的优先级,因此Bean1中的@Before先被织入。

3.jpg

Other @ControllerAdvice注解

在Spring 3.2中,新增了@ControllerAdvice、@RestControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping、@PostMapping, @GetMapping注解中。

  1. 异常处理
@ResponseBody
@ExceptionHandler(value = Exception.class)
public Map errorHandle(HttpRequest httpRequest,Exception ex) {
HashMap<String, Object> map = new HashMap<>();
map.put("100",100);
map.put("ex",ex.getMessage());
return map;
}
  1. 数据绑定
@ModelAttribute(name = "md")
public Map<String,Object> mydata() {
    HashMap<String, Object> map = new HashMap<>();
    map.put("age", 99);
    map.put("gender", "男");
    return map;
}
  1. 全局数据预处理
@InitBinder("date")
public void a(WebDataBinder binder) {
    binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
}