SpringBoot学习之整合AOP

共 7505字,需浏览 16分钟

 ·

2020-10-15 20:20

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

66套java从入门到精通实战课程分享

基于SpringBoot整合Aop记录日志

  • SpringBoot各版本参考文档

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

  • 查找引入依赖


  • 引入依赖




  •   
        org.springframework.boot
        spring-boot-starter-aop
      





  • 切面类




  •   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



  • 截图信息

  • 错误代码


  /**
  * @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切面通知执行顺序

  • 例图

通知注解中的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




版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:

https://blog.csdn.net/weixin_42586723/article/details/109017827






     



感谢点赞支持下哈 

浏览 36
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报