springboot使用AOP

springboot使用AOP

依赖引入

<!--添加aop依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

SpringMvc提供获取request和response对象

//这个RequestContextHolder是Springmvc提供来获得请求的东西
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
HttpServletResponse response = ((ServletRequestAttributes)requestAttributes).getResponse();

//从session里面获取对应的值
String str = (String) requestAttributes.getAttribute("name",RequestAttributes.SCOPE_SESSION);
System.out.println("uri==>"+request.getRequestURI());
System.out.println("url==>"+request.getRequestURL());

代码实操

package com.lwp.study.proxy.log;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.SourceLocation;
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.util.Arrays;
import java.util.List;

@Aspect
@Component
public class CustomAdvice {

    /**
     * 定义切面点
     */
    @Pointcut("execution(* com.lwp.study.controller.StudentRestFulController.*(..))")
    public void controllerLog(){

    }

    /**
     * 方法执行之前的切面处理
     * @param joinPoint
     */
    @Before("controllerLog()")
    public void before(JoinPoint joinPoint){
        //这个RequestContextHolder是Springmvc提供来获得请求的东西
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        System.out.println("uri==>"+request.getRequestURI());
        System.out.println("url==>"+request.getRequestURL());

        //获取请求的参数
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            System.out.println("args===>"+arg);
        }
        //获取签名信息
        Signature signature = joinPoint.getSignature();
        //目标类的类型 class com.lwp.study.controller.StudentRestFulController
        Class declaringType = signature.getDeclaringType();
        //目标的类型名称 com.lwp.study.controller.StudentRestFulController
        String declaringTypeName = signature.getDeclaringTypeName();
        //方法名称 addUser
        String name = signature.getName();
        //方法执行 method-execution
        String kind = joinPoint.getKind();

        System.out.println("方法执行之前");
    }

    /**
     * 方法执行之后的切面处理
     * @param joinPoint
     * @param returnObj
     */
    @AfterReturning(returning = "returnObj", pointcut="controllerLog()")
    public void after(JoinPoint joinPoint,Object returnObj){
        //返回值结果
        System.out.println("返回值结果==>"+returnObj);
        System.out.println("方法执行之后");
    }


    /**
     * 异常处理==》切面操作的类中抛出异常则会执行
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(pointcut = "controllerLog()", throwing = "ex")
    public void afterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + ex);
    }


    /**
     * 这个注解可以简单地看作@Before和@After的结合。这个注解和其他的比比较特别,它的方法的参数一定要是ProceedingJoinPoint,
     * 这个对象是JoinPoint的子类。我们可以把这个看作是切入点的那个方法的替身,这个proceedingJoinPoint有个proceed()方法,
     * 相当于就是那切入点的那个方法执行,简单地说就是让目标方法执行,然后这个方法会返回一个对象,
     * 这个对象就是那个切入点所在位置的方法所返回的对象。
     *
     * 除了这个Proceed方法(很重要的方法),其他和那几个注解一样。
     * @param joinPoint
     */
    @Around("controllerLog()")
    public Object around(ProceedingJoinPoint joinPoint){
        System.out.println("around执行前");
        try {
            //执行方法,接收对象为返回值
            Object proceed = joinPoint.proceed();
            System.out.println("around执行后");
            System.out.println("proceed==>"+proceed);
            return proceed;  //一定要返回,不然前端接收不到数据
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return null;
    }
}

同一个方法有多个@Aspect类拦截

单个Aspect肯定是和只有一个Aspect的时候的情况是一样的,但不同的Aspect里面的advice的顺序呢??答案是不一定,像是线程一样,没有谁先谁后,除非你给他们分配优先级,同样地,在这里你也可以为@Aspect分配优先级,这样就可以决定谁先谁后了。

优先级有两种方式:
实现org.springframework.core.Ordered接口,实现它的getOrder()方法
给aspect添加@Order注解,该注解全称为:org.springframework.core.annotation.Order

不管是哪种,都是order的值越小越先执行:
@Order(5)
@Component
@Aspect
public class Aspect1 {
    // ...
}

@Order(6)
@Component
@Aspect
public class Aspect2 {
    // ...
}
这样Aspect1就永远比Aspect2先执行了。

本文参考博客

https://www.cnblogs.com/wangshen31/p/9379197.html2
posted @ 2021-07-24 17:19  幸运刘  阅读(47)  评论(0)    收藏  举报