(Annotation)注解从认识到进阶

📅 发布时间:2026/10/15 6:38:27
(Annotation)注解从认识到进阶
注解(Annotation)一、基本概念1.1 定义注解就是附加在类、方法、变量、参数上面的「标记 / 元数据」本身不直接执行代码给程序编译器 / JVM / 框架看的额外信息。1.2 分类① 内置基础注解Override标记重写方法 →编译器看检查是否真的重写父类方法SuppressWarnings压制警告Deprecated标记过时方法这类大多生命周期是SOURCE编译完就丢掉运行时不存在。② 元注解用来修饰注解本身Target Retention元注解 注解的注解用来定义自定义注解的规则Target这个注解能贴在哪类 / 方法 / 字段Retention注解保留到哪个阶段SOURCE / CLASS / RUNTIMEDocumented生成 javadoc 时保留这个注解Inherited子类自动继承父类上的该注解Constraint声明需要进行校验③ 自定义注解用public interface定义。如果设置Retention(RetentionPolicy.RUNTIME)运行时可以用反射读到这个标记然后写业务逻辑AOP、SpEL 解析、缓存、权限。二、用法2.1 内置注解简单来说内置注解比如Override直接写在代码上即可OverridepublicvoidHelloWord(){System.out.println(你好世界);}2.2 元注解元注解就是用来定义注解用的它们不同于内置注解不会在方法上或者其它地方直接使用Override这个注解底层就是通过元注解修饰的Target(ElementType.METHOD)// 只能标注在方法Retention(RetentionPolicy.SOURCE)publicinterfaceOverride{}[!NOTE]Target表示该注解的适用范围ElementType是一个枚举类型里面有METHOD方法等范围Retention表示注解生效阶段Source就表示在源码有效编译后消失。Target使用是一个枚举类publicenumElementType{// 类、接口、枚举、记录TYPETYPE,// 成员变量 / 字段包括static变量FIELD,// 普通方法不是构造方法Override用的就是这个METHOD,// 方法的形参PARAMETER,// 构造器CONSTRUCTOR,// 局部变量方法内部定义的变量LOCAL_VARIABLE,// 注解类型本身注解上贴注解也就是元注解ANNOTATION_TYPE,// 包PACKAGE,// Java8新增泛型参数 T 的T上面TYPE_PARAMETER,// Java8新增泛型使用的地方比如 ListStringTYPE_USE,// Java9新增模块 module-info.javaMODULE,// Java16新增记录的组件 recordRECORD_COMPONENT}其中TYPE,METHOD,FIELD,PARAMETER比较常用TYPE类、接口、enum。比如Service、ComponentFIELD成员变量。Autowired写在字段上就是这个METHOD普通方法。Override、Transactional方法上PARAMETER方法参数。RequestParam[!TIP]此注解也可以指定多个如果在没有此元注解则表示该被修饰的注解适用范围是所有// 注解既能贴类上也能贴方法上Target({ElementType.TYPE,ElementType.METHOD})Retention使用也是枚举类publicenumRetentionPolicy{/** * 仅源码阶段有效编译成class文件直接丢弃 */SOURCE,/** * 保留到class字节码文件JVM加载类时不载入内存运行时反射取不到默认策略 */CLASS,/** * 保留到运行期JVM加载后还在内存可以通过反射读取注解 */RUNTIME}SOURCE只存在.java源码里编译后删掉。例子Override、SuppressWarnings、Lombok 注解Data作用对象编译器CLASS默认值不写 Retention 就用这个写入.class字节码但 JVM 加载类的时候不会把注解加载进内存反射拿不到。多用于编译期字节码增强很少手写默认就是这个RUNTIME编译进 class类加载后注解保留在内存运行时反射可以获取。例子Component、Transactional、自定义MyLog、CacheableSpring AOP、自定义注解、权限控制必须用 RUNTIMEConstraint使用需要自定义一个校验的规则规则写在后面的类Constraint(validatedByMobileValidator.class)2.3 自定义注解新建一个interfance类并且利用元注解指定适用范围以及生效阶段等可以在该注解内部加上属性等// 元注解只能贴方法上 运行时可反射读取Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceMyLog{// 注解属性带默认值Stringvalue()default;Stringdesc()default默认描述;}三、反射的应用只要Retention设置成RUNTIME我们就可以通过反射的机制获取此注解以及内部的成员属性硬编码直接获取// 获取方法MethodmethodTest.class.getDeclaredMethod(queryUser);// 判断是否有注解if(method.isAnnotationPresent(MyLog.class)){MyLogmyLogmethod.getAnnotation(MyLog.class);System.out.println(myLog.value());System.out.println(myLog.desc());}通过AOP机制获取// 切面通知Around(切入点表达式)publicObjectaround(JoinPointjoinPoint)throwsThrowable{// 获取当前拦截到的方法签名SignaturesignaturejoinPoint.getSignature();MethodSignaturemethodSignature(MethodSignature)signature;// 拿到Method对象MethodmethodmethodSignature.getMethod();// 这里的method 和上面getDeclaredMethod拿到的是**同一种对象**MyLogmyLogmethod.getAnnotation(MyLog.class);System.out.println(myLog.value());System.out.println(myLog.desc());returnjoinPoint.proceed();}