美文网首页
Spring AOP简单使用--@Aspect注解

Spring AOP简单使用--@Aspect注解

作者: 东南枝下 | 来源:发表于2021-01-10 23:31 被阅读0次

    每次想写切面时都会忘记细节,只能去翻以前的代码,很尴尬,在这里记录一下大致的使用。

    依赖

            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.2</version>
            </dependency>
    
    // 1、定义一个切面类,定义为组件,使用@Component和@Aspect注解
    @Component
    @Aspect
    // @Order定义优先级,值越小优先级越高
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public class AnnontationAdvice {
            /*
              有五种Advice,可以在切点上进行增强处理
              @Before : 在切点方法之前执行
              @After : 在切点方法之后执行
              @AfterReturning : 切点方法返回后执行,可以对返回值进行修饰
              @Around : 环绕通知,能控制切点执行前,执行后,甚至👎点函数是否要执行
              @AfterThrowing  :切点方法抛异常执行
            */
    
        // 2、定义切点,获取输入参数,也可以从JoinPoint中获取入参等详细信息,具体看下一个代码块
        @Before("execution(* com.jenson.chapter4.app.server.IAOPService.withAop*(..)) && args(name,age)")
        //3、如果切点为某个注解(@EnableHumpField)的函数,通常这种情况比较多
        // @Before("@annotation(com.jenson.chapter4.infra.annotation.EnableHumpField)")
        public void beforeAdvice(String name, Long age) {
    
            System.out.println("前置通知执行了  name:"+name+" age:"+age);
        }
    
        @After("execution(* com.jenson.chapter4.app.server.IAOPService.withAop*(..))")
        public void afterAdvice() {
            System.out.println("后置通知执行了");
        }
    
        @AfterReturning(value = "execution(* com.jenson.chapter4.app.server.IAOPService.withAop*(..))", returning = "result")
        public void afterReturnAdvice(JoinPoint joinPoint, String result) {
            System.out.println("返回通知执行了" + "运行业务方法放回结果为" + result);
                    return (result + "==被修饰过1");
        }
    
        @Around("execution(* com.jenson.chapter4.app.server.IAOPService.withAop*(..))")
        public String arondAdvvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
            String result = "";
            try {
                System.out.println("环绕通知开始执行了aaaa");
                long start = System.currentTimeMillis();
                result = (String) proceedingJoinPoint.proceed();
                long end = System.currentTimeMillis();
                System.out.println("环绕通知执行结束了bbbb");
                System.out.println("执行业务方法共计:" + (end - start) + "毫秒。");
            } catch (Throwable e) {
    
            }
            return (result + "==被修饰过2");
        }
    
        @AfterThrowing(value = "execution(* com.jenson.chapter4.app.server.IAOPService.withAop*(..))", throwing = "e")
        public void throwingAdvice(JoinPoint joinPoint, Exception e) {
            StringBuffer stringBuffer = new StringBuffer();
            stringBuffer.append("异常通知执行了.");
            stringBuffer.append("方法:").append(joinPoint.getSignature());
            System.out.println(stringBuffer.toString());
        }
    }
    
    

    从JoinPoint中获取入参等详细信息

    // 切点为一个注解
    @Before("@annotation(com.alm.ori.infra.annotation.ThisIsAnnotation)")
    public void beforeAdvice(JoinPoint joinPoint) {
        // 获取函数
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取所有注解
        Annotation[] annotations = methodSignature.getMethod().getAnnotations();
        // 获取某个注解(@RequestMapping)的信息
         joinPoint.getTarget().getClass().getAnnotation(RequestMapping.class);
        // 获取参数名
        String[] parameterNames = methodSignature.getParameterNames();
         // 获取参数
        Object[] objs = joinPoint.getArgs();
    }
    

    使用AOP写一个记录api日志的功能
    参考:https://github.com/xkcoding/spring-boot-demo/tree/master/demo-log-aop

    /**
     * 接口调用日志
     *
     * @author Jenson
     */
    @Aspect
    @Component
    @Slf4j
    public class ApiLogAspect {
    
       @AfterReturning(value = "execution(* com.jenson.something.api.controller.*.*Controller.*(..))", returning = "result")
       public void afterReturningLog(JoinPoint joinPoint, Object result) {
          try {
             final ApiLog l = this.generateApiLog(joinPoint, result);
             log.debug("Request Log Info : {}", JSON.toJSONString(l, SerializerFeature.DisableCircularReferenceDetect));
          } catch (Exception e) {
             log.error(e.getMessage());
          }
       }
    
       /**
        * 生成Api日志
        *
        * @param joinPoint 切入点
        * @param result    返回值
        * @return api日志
        */
       private ApiLog generateApiLog(JoinPoint joinPoint, Object result) {
          ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
          HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
          StringBuffer requestURL = request.getRequestURL();
          String requestMethod = request.getMethod();
          String currentThreadName = Thread.currentThread().getName();
          long currentThreadId = Thread.currentThread().getId();
          return ApiLog.builder()
                .requestUrl(requestURL.toString())
                .requestType(requestMethod)
                .threadId(String.valueOf(currentThreadId))
                .threadName(currentThreadName)
                .classMethod(String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                      joinPoint.getSignature().getName()))
                .requestParams(this.getNameAndValue(joinPoint))
                .result(result)
                .build();
       }
    
       /**
        * 获取方法参数名和参数值
        *
        * @param joinPoint 切入点
        * @return 请求参数
        */
       private Map<String, Object> getNameAndValue(JoinPoint joinPoint) {
    
          final Signature signature = joinPoint.getSignature();
          MethodSignature methodSignature = (MethodSignature) signature;
          final String[] names = methodSignature.getParameterNames();
          final Object[] args = joinPoint.getArgs();
    
          if (ArrayUtil.isEmpty(names) || ArrayUtil.isEmpty(args)) {
             return Collections.emptyMap();
          }
          if (names.length != args.length) {
             log.warn("{}方法参数名和参数值数量不一致", methodSignature.getName());
             return Collections.emptyMap();
          }
          Map<String, Object> map = Maps.newHashMap();
          for (int i = 0; i < names.length; i++) {
             map.put(names[i], args[i]);
          }
          return map;
       }
    
    }
    
    /**
     * 进入接口时日志记录对象
     *
     * @author Jenson
     */
    @Data
    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    public class ApiLog {
       /**
        * 请求Url
        */
       private String requestUrl;
       /**
        * 请求方式
        */
       private String requestType;
       /**
        * 线程id
        */
       private String threadId;
       /**
        * 线程号
        */
       private String threadName;
       /**
        * 类方法
        */
       private String classMethod;
       /**
        * 请求参数
        */
       private Object requestParams;
       /**
        * 返回参数
        */
       private Object result;
    }
    

    相关文章

      网友评论

          本文标题:Spring AOP简单使用--@Aspect注解

          本文链接:https://www.haomeiwen.com/subject/cqfraktx.html