JAVA自定义注解使用指南

 更新时间:2025年11月15日 08:49:38   作者:syf0824  
注解是一种特殊的接口,用于为Java代码提供元数据,它们不会直接影响代码的执行,但可以被编译器、开发工具或运行时环境读取和使用,本文给大家介绍JAVA自定义注解的相关知识,感兴趣的朋友一起看看吧

什么是注解?

注解是一种特殊的接口,用于为Java代码提供元数据。它们不会直接影响代码的执行,但可以被编译器、开发工具或运行时环境读取和使用。

Java内置了一些常用的注解,如:

@Override - 表示方法重写父类方法

@Deprecated - 表示代码已过时

@SuppressWarnings - 抑制编译器警告

注解的基本语法

定义注解

使用@interface关键字来定义注解:

public @interface AutoFill {
}

元注解

元注解是用来注解其他注解的注解,Java提供了以下几种元注解:

@Target - 指定注解可以应用的目标元素类型

@Retention - 指定注解的保留策略

@Documented - 表示注解应该被包含在Javadoc中

@Inherited - 表示注解可以被继承

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    /**
     * 数据库操作类型:INSERT、UPDATE
     */
    OperationType value();
}

示例代码展示了一个用于公共字段自动填充的自定义注解,@Target明确注解可在方法上使用,@Retention明确在程序运行时可见。

注解元素

注解中可以定义元素,这些元素可以有默认值:

public enum OperationType {
    /**
     * 更新操作
     */
    UPDATE,
    /**
     * 插入操作
     */
    INSERT
}

示例自定义注解中的value方法则用来返回上示枚举类型数据,明确 使用该注解的方法 的作用,使用方式如下:

/**
      * 更新员工信息
      * @param employee
      */
     @AutoFill(OperationType.UPDATE) 
     void updateById(Employee employee);

当注解只有一个方法且方法名为 value 时,使用时可以省略方法名,如果方法不叫 value,就必须明确指定方法名:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoFill {
    /**
     * 数据库操作类型:INSERT、UPDATE
     */
    OperationType type();
}
/**
      * 更新员工信息
      * @param employee
      */
     @AutoFill(type = OperationType.UPDATE) 
     void updateById(Employee employee);

自定义注解的使用

通过反射处理注解

我们可以使用反射机制在运行时读取和处理注解:

@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 公共字段自动填充切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {}
    /**
     * 公共字段自动填充
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) throws Throwable {
        log.info("公共字段自动填充通知开始");
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class);
        // 获取数据库操作类型
        Enum operationType = autoFill.value();
        // 从ThreadLocal中获取当前登录用户的id
        Long currentId = BaseContext.getCurrentId();
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 从joinPoint中获取参数
        Object[] args = joinPoint.getArgs();
        if(args==null || args.length==0){
            return;
        }
        // 从参数中获取实体对象
        Object entity = args[0];
        // 调用实体对象的方法,设置创建时间、创建人、更新时间、更新人
        if(operationType==OperationType.INSERT){
            try{
                Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
                Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
                setCreateTime.invoke(entity, now);
                setUpdateTime.invoke(entity, now);
                setCreateUser.invoke(entity, currentId);
                setUpdateUser.invoke(entity, currentId);
            }catch (Exception e){
                log.error("公共字段自动填充通知异常", e);
            }
        }else if(operationType==OperationType.UPDATE){
            try{
                Method setUpdateTime = entity.getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class);
                Method setUpdateUser = entity.getClass().getDeclaredMethod("setUpdateUser", Long.class);
                setUpdateTime.invoke(entity, now);
                setUpdateUser.invoke(entity, currentId);
            }catch (Exception e){
                log.error("公共字段自动填充通知异常", e);
            }
        }
    }
}

上述示例展示的是@AutoFill注解进行公共字段自动填充必要的切面类。

@Aspect

该注解用于声明切面类。

/**
     * 公共字段自动填充切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {}

这一部分用于声明哪些部分需要拦截。(在com.sky.mapper包下的所有类及其所有方法  被自定义注解(@AutoFill)所标注)

/**
     * 公共字段自动填充
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) throws Throwable

@Before: 表示这是一个前置通知,在目标方法执行之前运行。

autoFillPointCut(): 引用一个切点表达式,定义了哪些方法需要被拦截。

JoinPoint: AOP 连接点对象,可以获取被拦截方法的详细信息:方法名、参数、目标对象等。通过 joinPoint.getArgs() 获取方法参数。

MethodSignature signature = (MethodSignature)joinPoint.getSignature();
AutoFill autoFill= signature.getMethod().getAnnotation(AutoFill.class);
// 获取数据库操作类型
Enum operationType = autoFill.value();

joinPoint.getSignature(): 获取连接点的签名信息。

(MethodSignature): 强制转换为 MethodSignature 类型,因为 Spring AOP 只拦截方法。

signature.getMethod(): 获取被拦截的 Method 对象。

.getAnnotation(AutoFill.class): 从方法上获取 @AutoFill 注解。

autoFill.value(): 调用注解的 value() 方法,获取注解中定义的枚举值。

// 从joinPoint中获取参数
        Object[] args = joinPoint.getArgs();
        if(args==null || args.length==0){
            return;
        }
        // 从参数中获取实体对象
        Object entity = args[0];

利用从joinPoint中获取的参数获得原本方法中传递的实体对象。

Method setCreateTime = entity.getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class);
Method setCreateUser = entity.getClass().getDeclaredMethod("setCreateUser", Long.class);
setCreateTime.invoke(entity, now);
setCreateUser.invoke(entity, currentId);

利用反射为对象设置公共字段。

最终效果

@AutoFill注解能有效替代原本冗长且重复的公共字段设置代码。

到此这篇关于JAVA自定义注解全解的文章就介绍到这了,更多相关java自定义注解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java sm3加密算法的实现

    Java sm3加密算法的实现

    这篇文章主要介绍了Java sm3加密算法的实现,帮助大家更好的利用Java进行加密,感兴趣的朋友可以了解下
    2020-10-10
  • JDK8 中Arrays.sort() 排序方法详解

    JDK8 中Arrays.sort() 排序方法详解

    这篇文章主要介绍了JDK8 中Arrays.sort() 排序方法解读,本文先行介绍Arrays.sort()中影响排序方式的几个因素,影响因素主要为数组类型、数组大小,结合阈值对排序方式进行选择,需要的朋友可以参考下
    2023-05-05
  • SpringBoot项目打包发布到外部tomcat(出现各种异常的解决)

    SpringBoot项目打包发布到外部tomcat(出现各种异常的解决)

    这篇文章主要介绍了SpringBoot项目打包发布到外部tomcat(出现各种异常的解决),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • 基于Quartz定时调度任务(详解)

    基于Quartz定时调度任务(详解)

    下面小编就为大家带来一篇基于Quartz定时调度任务(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 解决RocketMQ的幂等性问题

    解决RocketMQ的幂等性问题

    重复消费因调用链路长、消息发送超时或消费者故障导致,通过生产者消息查询、Redis缓存及消费者唯一主键可以确保幂等性,避免重复处理,本文主要介绍了解决RocketMQ的幂等性问题,感兴趣的可以了解一下
    2025-07-07
  • 使用Java冻结Excel行和列的完整指南

    使用Java冻结Excel行和列的完整指南

    在日常数据处理和报表生成中,Excel 扮演着不可或缺的角色,然而,当面对包含成百上千行、几十乃至上百列的大型 Excel 文件时,反复滚动查看数据往往会带来极大的不便,所以本文旨在提供一份清晰、实用且基于 Java 的解决方案,帮助读者高效地实现 Excel 行和列的冻结操作
    2026-02-02
  • spring Security配置拦截规则小结

    spring Security配置拦截规则小结

    本文介绍了使用Spring Security解决后台管理系统在访问静态资源如图片时需要登录验证的问题,通过配置拦截规则,将静态资源路径添加到白名单,感兴趣的可以了解一下
    2025-09-09
  • Java实现abc字符串排列组合

    Java实现abc字符串排列组合

    这篇文章主要为大家详细介绍了JAVA实现abc字符串的排列组合,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • Springboot整合RabbitMq测试TTL的方法详解

    Springboot整合RabbitMq测试TTL的方法详解

    这篇文章主要介绍了Springboot整合RabbitMq测试TTL的设置,设置TTL一般由两种设置方法,设置整个队列的过期时间另一种设置单个消息的过期时间,通过示例图文相结合给大家介绍的非常详细,需要的朋友可以参考下
    2022-03-03
  • JAVA 并发容器的一些易出错点你知道吗

    JAVA 并发容器的一些易出错点你知道吗

    今天给大家带来的文章是Java并发编程的相关知识,文中对java同步容器与并发容器做了非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-09-09

最新评论