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;
    }
}
相关推荐
yufei-coder19 分钟前
C#基础语法
开发语言·c#·.net
数据龙傲天19 分钟前
1688商品API接口:电商数据自动化的新引擎
java·大数据·sql·mysql
长天一色19 分钟前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
_.Switch31 分钟前
Python机器学习模型的部署与维护:版本管理、监控与更新策略
开发语言·人工智能·python·算法·机器学习
醉颜凉34 分钟前
银河麒麟桌面操作系统修改默认Shell为Bash
运维·服务器·开发语言·bash·kylin·国产化·银河麒麟操作系统
NiNg_1_23439 分钟前
Vue3 Pinia持久化存储
开发语言·javascript·ecmascript
带带老表学爬虫1 小时前
java数据类型转换和注释
java·开发语言
qianbo_insist1 小时前
simple c++ 无锁队列
开发语言·c++
千里码aicood1 小时前
【2025】springboot教学评价管理系统(源码+文档+调试+答疑)
java·spring boot·后端·教学管理系统
cyt涛1 小时前
MyBatis 学习总结
数据库·sql·学习·mysql·mybatis·jdbc·lombok