Java 自定义注解的定义与运行时解析机制
元注解(Meta-Annotations)基础
在 Java 中,自定义注解的实现依赖于元注解。元注解是用于标注其他注解的特殊注解,java.lang.annotation 包中提供了四种核心元注解:
- @Retention:指定注解的生命周期。
RetentionPolicy.SOURCE:仅保留在源码阶段,编译后丢弃。RetentionPolicy.CLASS:保留在字节码文件中,但运行时无法通过反射获取(默认行为)。RetentionPolicy.RUNTIME:始终保留,运行时可以通过反射机制读取,这是开发自定义功能最常用的模式。
- @Target:定义注解可以应用的程序元素类型,例如
ElementType.FIELD(字段)、ElementType.METHOD(方法)、ElementType.TYPE(类或接口)等。 - @Documented:标记该注解是否应包含在生成的 JavaDoc 文档中。
- @Inherited:指示被标注的类,其子类会自动继承该注解。
定义自定义注解
以下示例通过模拟电子产品元数据管理,展示如何定义不同类型的注解:
// 定义产品品牌注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface BrandName {
// 默认属性名为 value,使用时可省略 key
String value() default "";
}
// 定义产品分类注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DeviceCategory {
public enum Category { PC, MOBILE, WEARABLE };
Category type() default Category.PC;
}
// 定义供应商详细信息注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface VendorInfo {
int code() default -1;
String provider() default "Unknown";
String location() default "Mainland China";
}
在实体类中应用注解
将定义好的注解应用到具体的业务模型字段上:
public class Computer {
@BrandName("ThinkPad")
private String modelName;
@DeviceCategory(type = DeviceCategory.Category.PC)
private String category;
@VendorInfo(code = 1024, provider = "Lenovo Group", location = "Beijing")
private String manufacturer;
// Getter 和 Setter 方法省略
}
运行时解析注解
核心逻辑在于通过 Java 反射 API 获取字段上的注解实例,并提取其属性值:
import java.lang.reflect.Field;
public class MetadataProcessor {
public static void parseDeviceMetadata(Class<?> clazz) {
// 获取类中声明的所有字段
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
// 解析 BrandName 注解
if (field.isAnnotationPresent(BrandName.class)) {
BrandName brand = field.getAnnotation(BrandName.class);
System.out.println("品牌名称: " + brand.value());
}
// 解析 DeviceCategory 注解
else if (field.isAnnotationPresent(DeviceCategory.class)) {
DeviceCategory category = field.getAnnotation(DeviceCategory.class);
System.out.println("设备分类: " + category.type());
}
// 解析 VendorInfo 注解
else if (field.isAnnotationPresent(VendorInfo.class)) {
VendorInfo vendor = field.getAnnotation(VendorInfo.class);
System.out.println("供应商代码: " + vendor.code() +
", 名称: " + vendor.provider() +
", 所在地: " + vendor.location());
}
}
}
public static void main(String[] args) {
parseDeviceMetadata(Computer.class);
}
}
通过这种方式,我们可以在运行时动态获取类元数据。这种机制是 Spring 依赖注入(DI)和面向切面编程(AOP)等核心功能的基础。通过反射处理注解,开发者可以实现高度解耦的业务逻辑,例如权限控制、日志记录或自动化数据校验。