Java 获取类或方法上的注解
获取方法
Class
Class.getAnnotations()
获取所有的注解,包括自己声明的以及继承的Class.getAnnotation(Class< A > annotationClass)
获取指定的注解,该注解可以是自己声明的,也可以是继承的Class.getDeclaredAnnotations()
获取自己声明的注解
Method
Method.getAnnotations()
获取所有的注解,包括自己声明的以及继承的Method.getAnnotation(Class< A > annotationClass)
获取指定的注解,该注解可以是自己声明的,也可以是继承的Method.getDeclaredAnnotations()
获取自己声明的注解
示例
//自定义注解A
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface A {
String value() default "";
}
//自定义注解B
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface B {
String value() default "";
}
//使用注解
@A("testClass")
public class TestService {
@B("testMethod")
public void sayHello() {
System.out.println("hello word");
}
}
//获取
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = TestService.class;
System.out.println(Arrays.toString(clazz.getAnnotations()));
System.out.println(clazz.getAnnotation(A.class));
System.out.println(Arrays.toString(clazz.getDeclaredAnnotations()));
System.out.println();
Method method = clazz.getMethod("sayHello", null);
System.out.println(Arrays.toString(method.getAnnotations()));
System.out.println(method.getAnnotation(B.class));
System.out.println(Arrays.toString(method.getDeclaredAnnotations()));
}
注意
- 注解只有被定义为
@Inherited
才可以被子类继承 - 当前类或方法没有被任何注解标注时,
getAnnotations()
和getDeclaredAnnotations()
返回空数组 - 方法
getAnnotation(Class< A > annotationType)
查询的注解不存在是会返回null
- 子类重写了父类的方法,注解无法被继承
获取不到注解信息
自定义注解
检查注解定义:
当注解未定义 @Retention(value = RetentionPolicy.RUNTIME)
时,无法获取到注解信息。
Annotation
类型可以被它们自己所标注。Java5.0
定义了4个标准的 meta-annotation
类型,分别是:Target
、Retention
、Documented
、Inherited
,它们被用来提供对其它 annotation
类型作说明。 这些类型和它们所支持的类在 java.lang.annotation
包中可以找到。
@Target
的用法:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。ElementType.ANNOTATION_TYPE
应用于注释类型声明ElementType.CONSTRUCTOR
构造方法声明ElementType.FIELD
应用于字段声明(包括枚举常量)ElementType.LOCAL_VARIABLE
应用于局部变量声明ElementType.METHOD
应用于方法声明ElementType.PACKAGE
应用于包声明ElementType.PARAMETER
应用于参数声明ElementType.TYPE
应用于类、接口(包括注释类型)或枚举声明
@Retention
的用法:指示注释类型的注释要保留多久。如果注释类型声明中不存在Retention
注释,则保留策略默认为RetentionPolicy.CLASS
RetentionPolicy.CLASS
编译器将把注释记录在类文件中,但在运行时JVM
不需要保留注释RetentionPolicy.RUNTIME
编译器将把注释记录在类文件中,在运行时JVM
将保留注释,因此可以反射性地读取RetentionPolicy.SOURCE
编译器要丢弃的注释
@Documented
的用法:指示某一类型的注释将通过javadoc
和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用Documented
来注释的,则其注释将成为注释元素的公共API
的一部分。Documented
是一个没有成员的注释。@Inherited
的用法:指示注释类型自动被子类继承。Inherited
也是一个没有成员的注释
注意,如果使用 @Inherited
注释类以外的任何事物都是无效的。还要注意,此元注释仅对从超类继承注释有效;对已实现接口的注释无效。
类被代理
当前类被代理时是获取不到注解信息的,那该如何获取注解信息呢?
正常情况下我们的类是 com.spc.job.canal.CanalHandler
这样的,但是如果被 AOP
代理过的类是 class com.spc.job.canal.CanalHandler$$EnhancerBySpringCGLIB$$5770166e
解决方式一
重新获取一个没有被代理的 Class
对象:
Class<?> clazz = bean.getClass();
String name = clazz.getName();
if (name.contains("$$EnhancerBySpringCGLIB") || name.contains("$$5770166e")) {
name = name.substring(0, name.indexOf("$$"));
}
try {
clazz = Class.forName(name);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e.getMessage());
}
System.out.println(Arrays.toString(clazz.getAnnotations()));
for (Method method : clazz.getMethods()) {
System.out.println(Arrays.toString(method.getAnnotations()));
}
解决方式二
使用 Spring
里面提供的 AnnotationUtils
来读取注解
//A 为注解信息
A a = AnnotationUtils.findAnnotation(method, A.class);