springboot自定义注解实现aop

增强方法也称为通知方法,指标注有@Before、@After、@AfterReturning、@AfterThrowing、@Around注解的Java方法。其中,有前置增强、后置增强、返回增强、异常增强和环绕增强五种增强方式。

一、目录结构

二、项目依赖

 <!--aop相关依赖 开始-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.8.9</version>
        </dependency>
        <!--aop相关依赖 结束-->

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
        <!--springboot-web依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

三、代码

自定义注解

package at.xx.annotation;

import java.lang.annotation.*;

/**
 * @description:触发aop的自定义注解
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
    String value() default "";
}

切面类

package at.xx.aspect;

import at.xx.annotation.MyAnnotation;
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.MethodSignature;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspect {
    @Before("@annotation(at.xx.annotation.MyAnnotation)")
    public void before(JoinPoint joinPoint) {
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        //获取方法签名(能得到方法的些信息,如:方法名)
        Signature signature = joinPoint.getSignature();
        //方法名称
        String name = signature.getName();
        System.out.println(name + "前置增强,方法参数:" + args[0] + args[1]);
    }

    @After("@annotation(at.xx.annotation.MyAnnotation)")
    public void after(JoinPoint joinPoint) {
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println(name + "后置增强,方法参数:" + args[0] + args[1]);
    }

    @AfterReturning(value = "@annotation(at.xx.annotation.MyAnnotation)", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println(name + "返回增强,方法结果:" + result);
    }

    /**
     *
     * @param joinPoint
     * @param e 通过该参数指定异常,触发该增强
     */
    @AfterThrowing(value = "@annotation(at.xx.annotation.MyAnnotation)", throwing = "e")
    public void AfterThrowing(JoinPoint joinPoint, NullPointerException e) {
        System.out.println("异常增强"+e);
    }

    @Around("@annotation(at.xx.annotation.MyAnnotation)")
   public Object around(ProceedingJoinPoint joinPoint){
        //方法返回值
        Object result=null;
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        args[0]="张子成";
        //获取方法签名
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //获取注解
        MyAnnotation annotation = signature.getMethod().getAnnotation(MyAnnotation.class);
        //获取注解参数值
        String value = annotation.value();
        //todo  原方法执行前增加的业务逻辑
        try {
             result = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //todo 原方法执行后增加的业务逻辑
        return result;
    }
}

controller 层(原有逻辑方法)

package at.xx.controller;

import at.xx.annotation.MyAnnotation;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Mr.Z
 * @Create 2023-01-29 21:03
 * @description:
 */
@RestController
public class AopController {
    @MyAnnotation
    @GetMapping("/test/before")
    public String testAop(String arr1,String arr2){
        System.out.println("方法运行");
        String s=null;
        System.out.println(arr1+arr2);
        //s.equals("x");
       // int i=1/0;
        return "aop";
    }
}

四、具体介绍

1、前置增强

前置增强(@Before,又称前置通知):在目标方法执行之前执行。

@Before("@annotation(at.xx.annotation.MyAnnotation)")
    public void before(JoinPoint joinPoint) {
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println(name + "前置增强,方法参数:" + args[0] + args[1]);
    }

2、后置增强

后置增强(@After,又称后置通知):在目标方法执行后执行,无论目标方法运行期间是否出现异常。

注意:后置增强无法获取目标方法执行结果,可以在返回增强中获取。

 @After("@annotation(at.xx.annotation.MyAnnotation)")
    public void after(JoinPoint joinPoint) {
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        //获取方法签名
        Signature signature = joinPoint.getSignature();
        String name = signature.getName();
        System.out.println(name + "后置增强,方法参数:" + args[0] + args[1]);
    }

3、返回增强

返回增强(@AfterReturning,又称返回通知):在目标方法正常结束后执行,可以获取目标方法的执行结果。

@AfterReturning(value = "@annotation(at.xx.annotation.MyAnnotation)", returning = "result")
    public void afterReturning(JoinPoint joinPoint, Object result) {
        System.out.println(name + "返回增强,方法结果:" + result);
    }

4、异常增强

异常增强(@AfterThrowing,又称异常通知):目标方法抛出异常之后执行,可以访问到异常对象,且可以指定在出现哪种异常时才执行增强代码。

/**
     *
     * @param joinPoint
     * @param e 通过该参数指定异常,触发该增强
     */
    @AfterThrowing(value = "@annotation(at.xx.annotation.MyAnnotation)", throwing = "e")
    public void AfterThrowing(JoinPoint joinPoint, NullPointerException e) {
        System.out.println("异常增强"+e);
    }

5、环绕增强

环绕增强:目标方法执行前后都可以织入增强处理。

@Around("@annotation(at.xx.annotation.MyAnnotation)")
   public Object around(ProceedingJoinPoint joinPoint){
        //方法返回值
        Object result=null;
        //获取方法参数
        Object[] args = joinPoint.getArgs();
        args[0]="张子成";
        //获取方法签名
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //获取注解
        MyAnnotation annotation = signature.getMethod().getAnnotation(MyAnnotation.class);
        //获取注解参数值
        String value = annotation.value();
        //todo  原方法执行前增加的业务逻辑
        try {

             result = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        //todo 原方法执行后增加的业务逻辑
        return result;
    }

五、使用场景及注意事项

使用场景:

在不改变原有代码的情况下,增加新的业务逻辑时使用aop(重点掌握@Around);

注意:

1、@Before、@After、@AfterReturning和@AfterThrowing修饰的方法可以通过声明JoinPoint 类型参数变量获取目标方法的信息(方法名、参数列表等信息);@Around修饰的方法必须声明ProceedingJoinPoint类型的参数,该变量可以决定是否执行目标方法;

2、@Before、@After、@AfterReturning和@AfterThrowing修饰的方法没有返回值;而@Around修饰的方法必须有返回值,返回值为目标方法的返回值;


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