使用自定义注解与Spring AOP 实现程序增强


前言

本文将通过自定义注解与Spring AOP实现Java的程序增强,会对涉及到的元注解切面进行简单的描述。


一、元注解是什么?

元注解(meta-annotation)的作用是在其他注解上注解,用来提供其他注解的类型说明。在自定义注解时,通常都需要使用元注解。本文仅介绍部分元注解,如需了解的小伙伴请自行查找。

@Target

@Target:注解用来限制注解的使用范围,即指定被修饰的注解能用于哪些程序单元

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

通过源码可知,@Target注解的 value 值是一个数组,这也就意味着注解的作用对象可以有多个。 其取值范围都在ElementType这个枚举之中:

枚举值功能描述
ElementType.Type用于修饰类、接口、注解或枚举类型
ElementType.FIELD用于修饰属性(成员变量),包括枚举常量
ElementType.METHOD用于修饰方法
ElementType.PAPAMETER用于修饰参数
ElementType.CONSTRUCTOR用于修饰构造方法
ElementType.LOCAL_VARIABLE用于修饰局部变量
ElementType.ANNOTATION_TYPE用于修饰注解类
ElementType.PACKAGE用于修饰包
ElementType.TYPE_PARAMETER用于标注类型参数(1.8之后版本)
ElementType.TYPE_USE能标注任何类型名称(1.8之后版本)

@Retention

@Retention:注解用于指定被修饰注解的生命周期。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

通过源码可知,@Retention注解的 value 其取值范围都在RetentionPolicy 这个枚举之中:

保留策略值功能描述
Retention.SOURCE注解编译时可见,编译完后就被丢弃,一般用于编译器做一些事情
Retention.CLASS注解在编译期完后存入.class文件中,运行时JVM不可获取注解信息,该策略值也是默认值
Retention.RUNTIME运行时JVM可以获取注解信息(反射),表示注解会一直起作用

二、具体实现

1.自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface VersionComparisonApi {
    String version() default "0";
}

2.切面类

@annotation来配置切点,代表我们的AOP切面会切到所有用 @VersionComparisonApi 注解修饰的类。

代码如下(示例):

@Slf4j
@Aspect
@Component
public class VersionComparisonAspect {

    @Before("@annotation(com.byx.cygnus.dm.controller.aoptest.VersionComparisonApi)")
    public Object appClientVersionCheck(JoinPoint joinPoint) throws Throwable {

        long begin = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        VersionComparisonApi versionComparisonApi = method.getAnnotation(VersionComparisonApi.class);
        String version = versionComparisonApi.version();
        log.info("============请求开始==========");
        log.info("请求链接:{}", request.getRequestURI().toString());
        log.info("接口描述:{}", version);
        log.info("请求类型:{}", request.getMethod());
        log.info("请求方法:{}.{}", signature.getDeclaringTypeName(), signature.getName());
        log.info("请求IP:{}", request.getRemoteAddr());
        log.info("请求入参:{}", JSON.toJSONString(joinPoint.getArgs()));
//        Object result = joinPoint.proceed(); // 环绕通知中用于执行被代理对象的方法
        long end = System.currentTimeMillis();
        log.info("请求耗时:{}ms", end - begin);
//        log.info("请求返回:{}", JSON.toJSONString(result));
        log.info("=============请求结束===========");
        return null;
    }
}

其中涉及到的AOP常用注解再次说明一下:

  • @Aspect : 指定切面类;
  • @Pointcut:公共切入点表达式
  • 通知方法
    • 前置通知(@Before) 目标方法执行之前,执行注解的内容
    • 后置通知(@After)目标方法执行之后,执行注解的内容
    • 返回通知 (@AfterReturning)目标方法返回后,执行注解的内容
    • 异常通知 (@AfterThrowing)目标方法抛出异常后,执行注解的内容
    • 环绕通知 (@Around)目标方法执行前后,分别执行一些代码

注意事项!!!

  • ProceedingJoinPoint只能用在around(环绕通知)中
    环绕通知=前置+目标方法执行+后置通知,proceed方法就是用于启动目标方法执行的
  • 定义好切片类后要将其加入Spring容器内才能使用(可以使用@Component注解)

3.测试类

@RestController
@RequestMapping("/AopTest")
public class Test {

    @VersionComparisonApi(version = "1") // 自定义注解使用
    @PostMapping("/test")
    public Area getArea(@RequestBody Area area){
        return area;
    }
}

在这里插入图片描述
在这里插入图片描述


总结

以上就是今天要讲的内容,本文仅仅简单介绍了实现自定义注解与AOP的过程,而其中的未提及的元注解与AOP相关需要小伙伴自行查阅。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值