Spring Boot中的切面AOP处理

DBC 1K 0

具体代码

温馨提示

代码里面注释已经非常清楚!

package com.example.test05.demo.config;

import com.example.test05.demo.model.UserDO;
import com.example.test05.demo.tool.JsonData;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;

/**
 * @author DBC
 * @date 2023/1/12 11:20
 * @network dbc655.top
 */
@Aspect
@Component
@Slf4j
public class LogAspectHandler {


    /*** 定义一个切面,拦截com.example.test05.demo.controller包和子包下的所有方法 */
    @Pointcut("execution(* com.example.test05.demo.controller..*.*(..))")
    public void pointcut() {
    }

    /**
     * 前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)
     * @param joinPoint
     */
    @Before("pointcut()")
    public void testBefore(JoinPoint joinPoint) {
        log.info("[testBefore方法]:进入!");
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        String declaringTypeName = signature.getDeclaringTypeName();
        log.info("[testBefore方法]:包名为:{},方法名为:{}", declaringTypeName, methodName);
        // 也可以用来记录一些信息,比如获取请求的url
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        //获取URL
        String requestURL = request.getRequestURL().toString();
        log.info("[testBefore方法]:请求的url地址为:{}",requestURL);
    }

    /**
     * 后通知(After (finally) advice):当某连接点退出的时候执行的通知(一定执行)
     * @param joinPoint
     */
    @After("pointcut()")
    public void testAfter(JoinPoint joinPoint) {
        log.info("[testAfter方法]:进入");
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        log.info("[testAfter方法]:{}执行完成", name);

    }

    /**
     * 返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回
     * @param joinPoint
     * @param result
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public void testAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("[testAfterReturning方法]:,返回参数为:{}", result);
        JsonData jsonData = (JsonData) result;
        UserDO userDO = (UserDO) jsonData.getData();
        userDO.setName("[testAfterReturning方法]:dbc升级版");
        userDO.setTime(new Date());
        log.info("[testAfterReturning方法]:编辑后的返回值为:{}", userDO);
    }

    /**
     * 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。 (它和返回后通知总是只执行一个)
     * @param joinPoint
     * @param ex
     */
    @AfterThrowing(value = "pointcut()", throwing = "ex")
    public void testAfterThrowing(JoinPoint joinPoint, Throwable ex) {
        log.info("[testAfterThrowing方法]:方法进入");
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        log.info("[testAfterThrowing方法]:{}执行出错,异常为:{}", name,ex.getMessage());
    }



}

简单测试一下

    @RequestMapping("/testJson")
    public JsonData testJson(int error) {
        if (error==1){
            int i = 1 / 0;
        }
        UserDO userPO = new UserDO();
        userPO.setName("dbc");
        return JsonData.buildSuccess(userPO);
    }

Spring Boot中的切面AOP处理插图

控制台输出

顺序执行切面,具体顺序如下图

Spring Boot中的切面AOP处理插图2

温馨提示

从上述结果看注解的执行顺序为 @Before -> @After -> @AfterReturning/ @AfterThrowing(这两个注解的方法任何时候只有一个生效,无异常则@AfterReturning生效,有异常则@AfterThrowing生效)

发表评论 取消回复
表情 图片 链接 代码

分享