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;
    }
}
相关推荐
guodingdingh40 分钟前
软件开发工作问题总结0718
java·开发语言·数据库
咖啡八杯2 小时前
GoF设计模式——解释器模式
java·后端·spring·设计模式
GuWenyue2 小时前
Cursor黑盒拆解!1套LangChain.js手写Mini编程Agent,自动生成React项目,效率提升60%
前端·数据库·人工智能
优橙教育3 小时前
5G网优培训 vs Java开发:转行选哪个?
java·开发语言·5g
糖果店的幽灵3 小时前
【DeepAgents 从入门到精通】Context Management 上下文管理
java·人工智能·后端·spring·中间件·langgraph·deepagents
腻害兔4 小时前
【若依项目-产品经理视角】RuoYi-Vue-Pro 源码拆解:字典、短信、邮件、通知——后台系统的“基础设施四件套“!
java·前端·vue.js·产品经理·ai编程
Miao121314 小时前
某海外住宿平台如何在大规模场景下实现指标一致性:Minerva 指标平台实践
大数据·数据库·人工智能
SeaTunnel4 小时前
从 Python Script 地狱到标准化数据集成框架
大数据·开发语言·python·程序员·代码·seatunnel
CodexDave4 小时前
MySQL事务隔离级别与MVCC机制解析
前端·数据库·mysql·nginx·性能优化·负载均衡
碎光拾影5 小时前
ARM交叉工具链各工具作用及IMX6ULL平台LED+蜂鸣器裸机程序实现
java·开发语言·数据库