注解本身不执行逻辑,其“方法”仅为属性声明语法;真正提取属性值必须通过反射调用AnnotatedElement接口(如getAnnotation())获取注解实例后访问属性,且注解生命周期须设为RUNTIME。

注解方法本身不执行逻辑,所谓“在注解方法中定义属性提取逻辑”是一种常见误解。注解只是元数据容器,它的“方法”其实是声明属性的语法形式,并非真正可调用的方法。真正的属性提取必须在外部——通过反射从被标注的元素(如类、方法、字段)上读取注解实例,再调用其属性方法获取值。
注解定义阶段:只声明属性,不写提取逻辑
自定义注解中的每个“方法”本质是属性声明,必须满足:
- 无参数(括号内为空),例如 String value(),不能写 String value(int x)
- 无异常声明(不能带 throws)
- 返回类型受限:基本类型、String、Class、枚举、其他注解、以及它们的数组
- 可选 default 值,如 int level() default 1
属性提取阶段:靠反射 + AnnotatedElement 接口
要拿到注解里的值,需在运行时操作被标注的目标对象:
- 获取目标元素:比如 Method method = clazz.getDeclaredMethod("doSomething")
- 检查是否标注:用 method.isAnnotationPresent(MyLog.class)
- 提取注解实例:MyLog anno = method.getAnnotation(MyLog.class)
- 调用属性方法:String desc = anno.value()、LogLevel lvl = anno.level()
关键前提:注解生命周期必须设为 RUNTIME
若想在运行时用反射提取,定义注解时必须加上:
- @Retention(RetentionPolicy.RUNTIME) —— 否则字节码里没有,反射拿不到
- @Target({ElementType.METHOD, ElementType.TYPE}) —— 明确它能标在哪
实际使用中常配合框架自动完成提取
纯手写反射提取较繁琐,生产环境通常交由框架处理:
- Spring AOP 中,在切面里通过 joinPoint.getSignature() 获取方法,再反射取注解
- Spring Boot 的 @ConfigurationProperties 或自定义 @Bean 初始化逻辑中解析类上注解
- JUnit5 扩展模型通过 ExtensionContext 读取测试方法上的自定义注解

















