Java 自定义注解

Java 自定义注解, 以及@interface @Target @Retention @Around @Before @After ProceedingJoinPoint JoinPoint 等用法

注解应用非常广泛,我们自定义注解能简化开发各种各种业务

一、关键字解释

(1) 定义注解时,关键字

@interface 来表示注解类的类型

@Target @Retention 这两个具体值,需要分析注解的应用场景来确定;

对于"调用方法时打印入参和出参"的例子,是在调用调用方法时,则使用RetentionPolicy.RUNTIME, 且作用于方法上,则使用ElementType.METHOD;

(2) 实现注解时,关键字

@Before、@After、@AfterReturning 方法的入参是JoinPoint类型

@Around 方法的入参是ProceedingJoinPoint类型

ProceedingJoinPoint继承了JoinPoint类型,并扩展出了proceed()方法,执行proceed()也就是执行原始的函数具体业务方法,可以通过JoinPoint对象获取一些请求上的参数,比如request,parms等;

执行顺序:

@Around >> @Before >> 被添加注解的方法业务执行 >> @After >> @AfterReturning

特别注意:

注解中,可以存在@Around、@Before 、@After或、@AfterReturning任意组合

注解中,存在@Around ,也存在@Before 、@After或、@AfterReturning时、会先执行@Around;

在@Around中,执行参数的ProceedingJoinPoint.proceed(), 会触发@Before 、"被添加注解的方法业务执行" 、@After、@AfterReturning的执行,

在@Around中,不执行参数的ProceedingJoinPoint.proceed(), 不会触发@Before 、"被添加注解的方法业务执行",特别注意;所以正常逻辑中,ProceedingJoinPoint.proceed()都应该触发执行。

@Around 的返回值应该为 "被添加注解的方法业务执行" 的返回值。通过获取Object bizData = ProceedingJoinPoint.proceed(), 也可以对返回值加工再返回;

三、代码实现

(1) 定义注解

java 复制代码
package com.xxxxx.annotation;

import java.lang.annotation.*;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface MethodParam {

    /**
     * 自定义方法, 日志描述信息, 可有可无
     *
     * @return
     */
    String description() default "";

    /**
     * 自定义方法1, 日志描述信息, 可有可无
     *
     * @return
     */
    String description1() default "";

    /**
     * 自定义方法2, 日志描述信息, 可有可无
     *
     * @return
     */
    String description2() default "";
}

其中description() description1() description2() 都是自定义方法(相当于调用注解时的传参),当业务需要就声明,不需要就无需声明

(2) 实现注解

java 复制代码
package com.xxxxx.annotation.annotationAspect;

import com.xxxxx.annotation.MethodParam;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class MethodParamAspect {

    /**
     * 声明切点
     */
    @Pointcut(value = "@annotation(com.xxxxx.annotation.MethodParam)")
    public void doPointCut() {
        System.out.print("执行doPointCut \n");
    }

    /**
     * 调用方法前后执行
     * @param joinPoint
     */
    @Around(value = "doPointCut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.print("执行doAround \n");

        //获取注解入参
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        MethodParam methodParamNew = method.getAnnotation(MethodParam.class);
        String description = methodParamNew.description();
        String description1 = methodParamNew.description1();
        String description2 = methodParamNew.description2();


        //被添加注解的方法业务执行
        Object bizData = joinPoint.proceed();

        //处理其他业务
        
        return bizData;
    }

    /**
     * 调用方法之【前】执行
     * @param joinPoint
     */
    @Before(value = "doPointCut()")
    public void doBefore(JoinPoint joinPoint){
        System.out.print("执行doBefore \n");
        //处理其他业务
    }


    /***
     * 调用方法之【后】执行
     *
     * @param joinPoint
     */
    @After(value = "doPointCut()")
    public void doAfter(JoinPoint joinPoint){
        System.out.print("执行doAfter \n");
        //处理其他业务
    }


    /***
     * @After执行之【后】执行
     *
     * @param joinPoint
     * @param res 具体业务的返回值 (可有可无)
     */
    @AfterReturning(value = "doPointCut()",returning = "res")
    public void doAfterReturning(JoinPoint joinPoint, String res){
        System.out.print("执行doAfterReturning \n");
        //处理其他业务
    }
}

(3) 使用注解

java 复制代码
package com.xxxxx.component;

import com.xxxxx.annotation.MethodParam;
import org.springframework.stereotype.Component;
import java.util.Random;

@Component
public class OrderComponent {

    @MethodParam(description = "aaa", description1 = "bbb", description2 = "ccc")
    public String testAnnotation(String val1, String val2){
        String aa = val1.concat(val2)
        .concat(String.valueOf(String.format("%04d",new Random().nextInt(9999))));
        System.out.print(aa + "\n");
        return aa;
    }
}
相关推荐
开源之眼5 分钟前
《github star 加星 Taimili.com 艾米莉 》为什么Java里面,Service 层不直接返回 Result 对象?
java·后端·github
Maori3161 小时前
放弃 SDKMAN!在 Garuda Linux + Fish 环境下的优雅 Java 管理指南
java
用户908324602731 小时前
Spring AI 1.1.2 + Neo4j:用知识图谱增强 RAG 检索(上篇:图谱构建)
java·spring boot
进击的丸子2 小时前
虹软人脸服务器版SDK(Linux/ARM Pro)多线程调用及性能优化
linux·数据库·后端
小王和八蛋2 小时前
DecimalFormat 与 BigDecimal
java·后端
beata2 小时前
Java基础-16:Java内置锁的四种状态及其转换机制详解-从无锁到重量级锁的进化与优化指南
java·后端
IT探险家2 小时前
你的第一个 Java 程序就翻车?HelloWorld 的 8 个隐藏陷阱
java
随风飘的云2 小时前
SpringBoot 的自动配置原理
java
SimonKing2 小时前
觅得又一款轻量级数据库管理工具:GoNavi
java·后端·程序员
Seven973 小时前
BIO详解:解锁阻塞IO的使用方式
java