SpringBoot学习之整合AOP

基于SpringBoot整合Aop记录日志

  • SpringBoot各版本参考文档

    https://docs.spring.io/spring-boot/docs/

  • 查找引入依赖
    SpringBoot查找Aop依赖

  • 引入依赖

    
    
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>
    
    
    
  • 切面类

    
    
      package link.lycreate.springbooteasyexceldemo.aspect;
    
      import lombok.extern.slf4j.Slf4j;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.aspectj.lang.reflect.MethodSignature;
      import org.springframework.stereotype.Component;
      import org.springframework.web.context.request.RequestAttributes;
      import org.springframework.web.context.request.RequestContextHolder;
      import org.springframework.web.context.request.ServletRequestAttributes;
    
      import javax.servlet.http.HttpServletRequest;
      import java.lang.reflect.Method;
      import java.util.Arrays;
    
      /**
      * @ClassName LogAspect
      * @Description TODO 日志切面类$
      * @Author charlesYan
      * @Date 2020/10/9 12:53
      * @Version 1.0
      **/
      @Aspect  // 声明是一个切面组件
      @Component // 加入到IOC容器
      @Slf4j  // 等同于 private final Logger logger = LoggerFactory.getLogger(XXX.class);
      public class LogAspect {
    
          /**
          * @Author charlesYan
          * @Description // 指定切入点表达式,拦截那些方法,即为哪些类生成代理对象
          *      第一*表示匹配任何返回值的方法
          *      第二*表示匹配controller包下的所有类
          *      第三*表示匹配类下的所有方法
          *      ..表示任何个数参数,和如何类型的参数
          **/
          //@Pointcut("execution(* link.lycreate.springbooteasyexceldemo.controller.*.*(..))")
          @Pointcut("@annotation(link.lycreate.springbooteasyexceldemo.aspect.LogFilter)") //在所有标记指定注解的方法上拦截
          public void logPointCut(){}
    
          /**
          * @Author charlesYan
          * @Description //前置通知:在目标方法执行前调用
          **/
          @Before("logPointCut()")
          public void before(JoinPoint joinPoint){
              System.out.println("---------------Before Begin CurrentTime = " + System.currentTimeMillis());
              /*获取当前请求的HttpServletRequest*/
              RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
              HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
    
              log.info("URL-->"+request.getRequestURL().toString());
              log.info("IP-->"+request.getRemoteAddr());
              log.info("HTTP_Method-->"+request.getMethod());
              log.info("Request_args-->"+ Arrays.toString(joinPoint.getArgs()));
    
              System.out.println("---------------Before End CurrentTime = " + System.currentTimeMillis());
    
          }
    
          /**
          * @Author charlesYan
          * @Description //返回通知 在目标方法执行后调用,若目标方法出现异常,则不执行
          **/
          @AfterReturning(value = "logPointCut()",returning = "obj")
          public void afterReturning(JoinPoint joinPoint,Object obj){
              System.out.println("---------------AfterReturn CurrentTime = " + System.currentTimeMillis());
    
          }
    
          /**
          * @Author charlesYan
          * @Description //后置通知:无论目标方法在执行过程中是否出现异常都会在它之后调用
          **/
          @After("logPointCut()")
          public void after(JoinPoint joinPoint){
              System.out.println("---------------After CurrentTime = " + System.currentTimeMillis());
          }
    
          /**
          * @Author charlesYan
          * @Description //异常通知:目标方法抛出异常时执行
          **/
          @AfterThrowing(value = "logPointCut()", throwing = "ex")
          public void afterThrowing(JoinPoint joinPoint,Exception ex){
              System.out.println("---------------AfterThrowing CurrentTime = " + System.currentTimeMillis());
          }
    
          /**
          * @Author charlesYan
          * @Description //环绕通知:是前面四个通知的结合体
          *         需要在方法之前执行,可以写在joinPoint.procedd();之前
          *         需要在方法之后执行,可以写在joinPoint.procedd();之后
          **/
          @Around("logPointCut()")
          public void around(ProceedingJoinPoint joinPoint) throws Throwable {
    
              // 获取目标方法的名称
              String methodName = joinPoint.getSignature().getName();
              // 获取方法传入参数
              Object[] params = joinPoint.getArgs();
              MethodSignature signature = (MethodSignature) joinPoint.getSignature();
              Method method = signature.getMethod();
              // 获取方法上LogFilter注解
              LogFilter logFilter = method.getAnnotation(LogFilter.class);
              String value = logFilter.value() ;
              log.info("模块描述:"+value);
              System.out.println("---------------Around Before CurrentTime = " + System.currentTimeMillis() + " method name:" + methodName + " args:" + params[0]);
              // 执行源方法
              joinPoint.proceed();
              System.out.println("---------------Around After CurrentTime = " + System.currentTimeMillis() + " method name:" + methodName + " args:" + params[0]);
          }
      }
    
    
    
    
  • 自定义注解

    
    
      /**
      * @ClassName LogFilter
      * @Description TODO 自定义日志注解类$
      * @Author charlesYan
      * @Date 2020/10/11 17:59
      * @Version 1.0
      **/
    
      @Target(ElementType.METHOD)//Target注解决定LogFilter注解可以加在哪些成分上,如加在类身上,或者属性身上,或者方法身上等成分
      @Retention(RetentionPolicy.RUNTIME)//Retention注解括号中的"RetentionPolicy.RUNTIME"意思是让LogFilter这个注解的生命周期一直程序运行时都存在
      @Documented
      public @interface LogFilter {
    
          String value() default "";
      }
    
    
    
    
  • 请求方法

    
      @LogFilter("保存请求日志")
      @RequestMapping(path = "/saveRequestLog",method = RequestMethod.POST)
      public String saveRequestLog(@RequestParam("name")String name){
          return "请求成功:" + name;
      }
    
    
    
  • 测试方式
    切面测试请求

报错信息

方法参数未声明

  • 报错信息

    
      Caused by: java.lang.IllegalArgumentException: error at ::0 formal unbound in pointcut
    
    
    
  • 截图信息
    SpringBoot整合AOP报错一

  • 错误代码

    
      /**
      * @Author charlesYan
      * @Description //返回通知 在目标方法执行后调用,若目标方法出现异常,则不执行
      **/
      @AfterReturning("logPointCut()")
      public void afterReturning(JoinPoint joinPoint,Object obj){
          System.out.println("---------------AfterReturn CurrentTime = " + System.currentTimeMillis());
    
      }
    
    
  • 正确代码

    
      /**
      * @Author charlesYan
      * @Description //返回通知 在目标方法执行后调用,若目标方法出现异常,则不执行
      **/
      @AfterReturning(value = "logPointCut()", returning = "obj")
      public void afterReturning(JoinPoint joinPoint,Object obj){
          System.out.println("---------------AfterReturn CurrentTime = " + System.currentTimeMillis());
    
      }
    
    
    
  • 原因分析

    
      新增的方法参数未赋值
    
    
    

总结

Aop切面通知执行顺序

  • 例图
    AOP切面类通知执行顺序

通知注解中的value属性补充

  • 自定义注解

    
      //注解实体类
      package com.trip.demo;
    
      import java.lang.annotation.ElementType;
      import java.lang.annotation.Retention;
      import java.lang.annotation.RetentionPolicy;
      import java.lang.annotation.Target;
    
    
      @Retention(RetentionPolicy.RUNTIME)
      @Target({ ElementType.METHOD })
      public @interface SMSAndMailSender {
    
          /*短信模板String格式化串*/
          String value() default "";
    
          String smsContent() default "";
    
          String mailContent() default "";
          /*是否激活发送功能*/
          boolean isActive() default true;
          /*主题*/
          String subject() default "";
    
      }
    
    
    
    
  • 切面类中的切面方法

    
      /**
      * 在所有标记了@SMSAndMailSender的方法中切入
      * @param joinPoint
      * @param obj
      */
      @AfterReturning(value="@annotation(com.trip.demo.SMSAndMailSender)", returning="obj")
      public void afterReturning(JoinPoint joinPoint,Object obj){
          System.out.println("---------------AfterReturn CurrentTime = " + System.currentTimeMillis());
    
      }
    
    

参考链接

  • SpringBoot整合Aop

    https://www.cnblogs.com/fernfei/p/12092510.html

  • SpringBoot整合aop

    https://www.cnblogs.com/myitnews/p/11848159.html

  • SpringBoot 通过自定义注解实现AOP切面编程实例

    https://www.cnblogs.com/lingyejun/p/9941350.html

  • SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务

    https://my.oschina.net/cicadasmile/blog/3073069

  • 浅谈Spring AOP 面向切面编程 最通俗易懂的画图理解AOP、AOP通知执行顺序~

    https://www.cnblogs.com/ChromeT/p/11823735.html

  • @interface 注解详解

    https://blog.csdn.net/u010882691/article/details/82427520

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值