自定义注解实现AOP编程的最佳实践

        前提:导入AOP的Maven坐标,无需指定版本

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

1、创建自定义注解

  • @Target(ElementType.METHOD):
    • 指定了这个注解只能用来标注方法,不能用于类、字段等其他元素。
  • @Retention(RetentionPolicy.RUNTIME):
    • 表示这个注解在运行时保留,可以通过反射机制读取,允许在程序运行时通过反射获取注解信息。
  • type():
    • 该注解的唯一元素,类型为String默认为空字符串,可以用于区分被注解方法的类型,以便执行不同的处理逻辑。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    /**
     * 用于区分被注解方法的类型,来执行不同逻辑
     * @return 切入方法类型
     */
    String type() default "";
}

2、编写AOP切面类

  • @Component:
    • 将该类标记为Spring组件,由Spring容器管理,使其能够被自动扫描并注册为bean。
  • @Aspect:
    • 声明这是一个切面类,Spring AOP会识别这个注解并处理其中定义的切点。
  • @Slf4j:
    • Lombok注解,自动生成日志记录器(Logger),可以使用log变量记录日志。
  • @Before:
    • 定义前置通知,在目标方法执行前运行,使用切入点表达式@annotation(...)指定只拦截带有特定注解的方法。
    • 这里使用的是@Before前置通知,除了该注解还有@After、@Around、@AfterThrowing、@AfterReturning注解可根据需要进行调整。

通知类型

适用场景

@Before

参数校验、权限检查、日志记录

@AfterReturning

结果处理、成功日志记录

@AfterThrowing

异常处理、错误日志

@After

资源清理、审计日志

@Around

事务管理、缓存、性能监控

  • JoinPoint参数:
    • 提供对连接点(被拦截方法)的访问,可以获取方法签名、参数、目标对象等信息。
@Component
@Aspect
@Slf4j
public class CustomAop {
    @Before("@annotation(自定义注解相对路径.CustomAnnotation)")
    public void before(JoinPoint joinPoint) throws NoSuchMethodException {
        // 获取切入点的签名信息(org.aspectj.lang.reflect.MethodSignature)
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法名称(如果此时使用这个对象获取注解,会返回null,因为代理对象的方法上不会有注解)
        Method method = methodSignature.getMethod();
        // 获取目标类(反射)
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 反射从目标类中获取方法
        Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
        CustomAnnotation annotation = targetMethod.getAnnotation(CustomAnnotation.class);
        // 根据切入点不同来执行不同逻辑
        switch (annotation.type()) {
            case "1":
                方法1(需要的参数);
                break;
            case "2":
                方法2(需要的参数);
                break;
            case "3":
                方法3(需要的参数);
                break;
            default:
                break;
        }
    }
    
    /**
     * 实现方法1的逻辑
     * @param 需要的参数
     */
    private void 方法1(需要的参数) {
        // ... 具体逻辑 ...
    }

    /**
     * 实现方法2的逻辑
     * @param 需要的参数
     */
    private void 方法2(需要的参数) {
        // ... 具体逻辑 ...
    }

    /**
     * 实现方法3的逻辑
     * @param 需要的参数
     */
    private void 方法3(需要的参数) {
        // ... 具体逻辑 ...
    }
}

3、实现Demo

        示例:在保存接口通过前置通知注解切入进行权限校验

/**
* 自定义注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    /**
     * 用于区分被注解方法的类型,来执行不同逻辑
     * @return 切入方法类型
     */
    String type() default "";
}

/**
* AOP切面类
*/
@Component
@Aspect
@Slf4j
public class CustomAop {
    @Before("@annotation(自定义注解相对路径.CustomAnnotation)")
    public void before(JoinPoint joinPoint) throws NoSuchMethodException {
        // 获取切入点的签名信息
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法名称(如果此时使用这个对象获取注解,会返回null,因为代理对象的方法上不会有注解)
        Method method = methodSignature.getMethod();
        // 获取目标类(反射)
        Class<?> targetClass = joinPoint.getTarget().getClass();
        // 反射从目标类中获取方法
        Method targetMethod = targetClass.getMethod(method.getName(), method.getParameterTypes());
        CustomAnnotation annotation = targetMethod.getAnnotation(CustomAnnotation.class);
        // 根据切入点不同来执行不同逻辑
        switch (annotation.type()) {
            case "save":
                PermissionVerification();
                break;
            default:
                break;
        }
    }
    
    /**
     * 实现权限校验逻辑
     */
    private void PermissionVerification() {
        // ... 权限校验逻辑 ...
    }
}

@RestController
@RequestMapping("/demo")
@Slf4j
public class DemoController {

    @Autowired
    private DemoService demoServiceImpl;

    @PostMapping("/save")
    @CustomAnnotation(type = "save")
    public void saveBatchJob() {
        demoServiceImpl.saveBatchJob();
    }
}

文章内容若存在错误或需改进的地方,欢迎大家指正!非常感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值