Java基础|详解JDK自定义注解

📫 作者简介:「六月暴雪飞梨花」,专注于研究Java,就职于科技型公司后端工程师
🏆 近期荣誉:华为云云享专家、阿里云专家博主、腾讯云优秀创作者、腾讯云TDP-KOL、ACDU成员、墨天轮技术专家博主
🔥 三连支持:欢迎 ❤️关注、👍点赞、👉收藏三连,支持一下博主~

概述

在 Java 开发中,自定义注解(Annotation)是一种元编程机制,广泛用于框架设计、代码增强(如 AOP)、参数校验、权限控制、日志埋点等场景。大型的框架工具,如Spring、MyBatis、Hibernate 都大量使用注解机制,一些我们熟知的第三方工具(Hutool、Lombok)也都是用了大量的注解机制来增强和扩展应用。

1 关于自定义注解

一般来说,常见的自定义注解基本的语法包括
● @Target 注解使用的目标(类、方法、字段等)
● @Retention 保留策略(源码、类文件、运行时)
● @Documented 是否包含在 Javadoc 中
● @Inherited 子类是否可以继承父类上的注解

自定义注解一般的获取方式是结合反射读取注解,而在使用方向上结合 Spring AOP 使用注解是最多的,Spring已经应用在各类Java语言中的架构中。

2 Retention注解

定义

@Retention 是一个元注解(Meta‐annotation),来源于java.lang.annotation.Retention,用来标记一个注解自身应当被保留到哪个阶段(源码/字节码/运行时),他只能用在其他注解的定义上。
一张图来看下Retention注解RetentionPolicy中的参数。
在这里插入图片描述

参数详解

RetentionPolicy 定义了注解(@interface)在 Java 程序中的保留级别或者说是保留策略,也就是注解信息在什么阶段可见、可用。它包含三个枚举值SOURCE、CLASS、RUNTIME:

public enum RetentionPolicy {
    SOURCE,
    CLASS,
    RUNTIME
}

● SOURCE:注解仅在源代码中可见,编译时即被丢弃,生成的 .class 文件和运行时都不可见。
● CLASS:注解在编译后保存在 .class 字节码文件中,但 JVM 加载类时并不保留(即默认行为)。
● RUNTIME:注解在编译后保存在 .class 文件中,并且在运行时通过反射依然可访问。

案例测试
为了更好的理解Retention注解,可以参看下代码示例。

package com.liu.aop;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

/**
 * <p> RetentionTest </p>
 * class
 * TODO
 *
 * @author Aion.Liu
 * @version v1.0.0
 * @since 2025/5/21 09:07
 */
public class RetentionTest {

    @SourceOnly
    @ClassOnly
    @RuntimeVisible
    public void test() {
    }

    public static void main(String[] args) throws Exception {
        // 仅 RuntimeVisible 会被反射读取到
        Method m = RetentionTest.class.getMethod("test");
        System.out.println("SOURCE present: " + m.isAnnotationPresent(SourceOnly.class));
        System.out.println("CLASS present:  " + m.isAnnotationPresent(ClassOnly.class));
        System.out.println("RUNTIME present:" + m.isAnnotationPresent(RuntimeVisible.class));
    }
}


// 仅源码阶段
@Retention(RetentionPolicy.SOURCE)
@interface SourceOnly { }

// 编译后保留,但运行时不可见
@Retention(RetentionPolicy.CLASS)
@interface ClassOnly { }

// 运行时可见
@Retention(RetentionPolicy.RUNTIME)
@interface RuntimeVisible { }

打印结果如下

/xxx/jdk1.8.0_321.jdk/Contents/Home/bin/java - ……
com.liu.aop.RetentionTest
SOURCE present: false
CLASS present:  false
RUNTIME present:true

注意⚠️:

  1. 只有标注了 @Retention(RetentionPolicy.RUNTIME) 的注解,才可以通过反射 API(Annotation[], getAnnotation() 等)读取。
  2. 默认策略:如果没有声明 @Retention,注解的默认保留策略是 CLASS。
  3. 性能考虑:过多 RUNTIME 注解可能增加运行时反射成本,慎用。
  4. 兼容性:使用 SOURCE 策略时,IDE 和编译器插件需同时生效,否则注解处理器可能无法触发。

3 Target注解

定义

@Target 是用来指定自定义注解可以应用于哪些Java 元素的元注解(Meta-annotation),它定义了注解的作用范围,帮助编译器在错误的地方使用注解时给出提示。
一张图来看下Target注解ElementType中的参数(注意:图中包括JDK 1.5 - JDK16之间注解参数值)。
在这里插入图片描述

参数详解

@Target 注解参数是ElementType,他是一个枚举值,ElementType 定义了所有可用的目标类型,一共12种(截止到JDK21,)。

public enum ElementType {
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,
    TYPE_PARAMETER, 	// JDK 8
    TYPE_USE, 				// JDK 8
    MODULE, 					// JDK 9
    RECORD_COMPONENT; // JDK 16
}

注意⚠️

  1. 在使用时可以存在并存的情况,例如 METHOD 和 PARAMETER可以同时应用。

案例测试
Target注解只能应用在类和方法上面,在字段或参数上使用会编译报错。

// 自定义注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Audit {
    String action();
}

// 应用在类名称上
@Audit(action = "UserService")
public class UserService { ... }

public class OrderService {

    // 应用在方法上
    @Audit(action = "createOrder")
    public void create() { ... }
}

4 Documented注解

定义

在 Java 中,@Documented 是一个元注解(meta-annotation),用于指示某个注解类型是否应该被包含在 Javadoc 等生成的文档中。它是 Java 注解机制的一部分,定义在 java.lang.annotation 包中。

可从源代码中查看定义,当定义一个自定义注解,并在其上添加了 @Documented,任何使用了该注解的地方,在生成 Javadoc 时都会包含该注解。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

案例测试

// 1. 定义时使用Documented注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ApiDescription {
    String value();
}


// 2. 在类中使用自定义注解
@ApiDescription("注解描述。")
public class UserController {
}


// 3. 在shell中执行命令,生成的 HTML 文档中将包含注解 @ApiDescription 的信息。
javadoc -d doc UserController.java

5 Inherited注解

元注解(meta-annotation),它控制一个注解是否会被子类继承。
● @Inherited 只能用在自定义注解的定义上;
● 它表示:如果某个类使用了某个带有 @Inherited 的注解,那么它的子类也会自动继承该注解;
● 仅对类(class)有效,对方法、字段、构造器等无效。

总结使用范围

自定义注解一般结合 Spring Boot + AOP 实现:
● 登录校验:@LoginRequired
● 权限控制:@Permission(“admin”)
● 接口限流:@RateLimit(limit = 5, seconds = 60)
● 日志埋点:@TrackEvent(name = “点击提交”)
上述这些也都是在Java语言中,使用Spring框架使用的常用方式。


欢迎关注博主 「六月暴雪飞梨花」 或加入【六月暴雪飞梨花社区】一起学习和分享Linux、C、C++、Python、Matlab,机器人运动控制、多机器人协作,智能优化算法,滤波估计、多传感器信息融合,机器学习,人工智能等相关领域的知识和技术。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六月暴雪飞梨花

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值