Java注解

注解的本质

注解本质是一个继承java.lang.annotation.Annotation的特殊接口,通过@interface关键字定义。
在编译阶段,java注解会被编译成一个继承 java.lang.annotation.Annotation 的特殊接口,并生成对应属性的抽象方法。

注解本质是一个继承自Annotation接口的动态代理对象,通过@interface关键字定义。
在运行阶段,通过JDK动态代理生成注解接口的实现类实例,通过反射调用AnnotationInvocationHandler.invoke()方法实现属性访问。

元注解

  • @Retention:定义注解生命周期。定义保留策略。
    • SOURCE:仅存在于源码(编译时丢弃,如@Override)。
    • CLASS:保留在字节码(默认值,运行时不可读取)。
    • RUNTIME:运行时可通过反射获取(框架常用)。
  • @Target:限制注解可应用的位置(类、方法、字段等)。
  • @Inherited:允许子类继承父类的注解。
  • @Documented:将注解包含在Javadoc中。

注解的存储与解析

  • 字节码存储:注解信息以键值对形式存储在字节码的RuntimeVisibleAnnotations属性中。(编译时)
  • AnnotationParser解析:JVM通过sun.reflect.annotation.AnnotationParser在运行时解析字节码中的注解数据,生成动态代理对象。(运行时)
  • 常量池映射:注解的成员值通过常量池(Constant Pool)存储,代理类通过memberValues(Map结构)关联成员名与值。

动态代理与反射机制

  • 代理对象生成:通过Proxy.newProxyInstance()生成注解接口的代理实例,绑定AnnotationInvocationHandler。
  • 方法调用流程
    • 调用注解方法(如value())时,代理类触发AnnotationInvocationHandler.invoke()。
    • 通过Class.getAnnotation()等反射API获取注解对象,实际返回的是动态代理实例。从memberValues中获取成员值并返回。

底层实现原理

Java注解的底层实现结合了元数据存储、反射和动态代理技术:

  • 定义阶段:通过元注解声明行为和存储策略。
  • 编译阶段:注解信息写入字节码
  • 运行时:通过反射动态代理解析字节码,生成代理对象并操作成员值。

自定义注解

实现@interface,并用元注解@Retention与@Target修饰。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface LogExecutionTime {
    String prefix() default "";
} 

典型运用场景

  • 日志记录:通过AOP在方法执行前后记录日志,结合自定义注解标记需记录的方法。
  • ​权限控制:在Controller方法上标注权限注解,结合拦截器或AOP实现动态权限校验。
  • 数据校验:定义字段级注解(如@NotNull),通过Hibernate Validator等工具在运行时校验输入

通过反射API获取类、方法、字段等元素上的注解信息。

  • 1.获取类上的注解

    Class<?> clazz = MyClass.class;
    if (clazz.isAnnotationPresent(MyAnnotation.class)) {
        MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class);
        System.out.println("Class Annotation Value: " + annotation.value());
    }
    
  • 2.获取方法上的注解

    Method method = clazz.getDeclaredMethod("myMethod");
    if (method.isAnnotationPresent(MyAnnotation.class)) {
        MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
        System.out.println("Method Annotation Value: " + annotation.value());
    }
    
  • 3.获取字段上的注解

    Field field = clazz.getDeclaredField("myField");
    if (field.isAnnotationPresent(MyAnnotation.class)) {
        MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);
        System.out.println("Field Annotation Value: " + annotation.value());
    }
    
posted @ 2025-03-14 17:43  抒写  阅读(50)  评论(0)    收藏  举报