目录

  • 如何自定义组合注解
  • 通过反射解析组合注解
  • 使用 Spring 提供的工具类解析组合注解


如何自定义组合注解

在自定义注解时,需要为注解声明两个很重要的元注解:

  • @Retention:声明注解的生命周期
  • @Target:声明可以注解在哪些元素之上

自定义注解 @Retention 基本都是设置为 RetentionPolicy.RUNTIME,表明注解可以保留到运行期间。而 @Target 则可以选择多个元素。

元素

说明

ElementType.TYPE

注解在类、接口、枚举上

ElementType.FIELD

注解在类中的字段上

ElementType.METHOD

注解在类中的方法上

ElementType.PARAMETER

注解在方法的参数前

ElementType.CONSTRUCTOR

注解在类中构造方法上

ElementType.LOCAL_VARIABLE

注解在局部变量前

ElementType.ANNOTATION_TYPE

注解在注解上

ElementType.PACKAGE

注解在包名前

@Target 设置为 ElementType.ANNOTATION_TYPE 时,则表示当前注解可以声明在其它注解之上,这就是组合注解。

接下来通过代码演示如何自定义一个组合注解:

1、自定义一个注解 AnnoA,设置 @TargetElementType.ANNOTATION_TYPE

@Target({ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AnnoA {

    String value();

}

2、自定义另外一个注解 AnnoB,在注解上声明 @AnnoA,形成组合注解。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AnnoA("A")
public @interface AnnoB {

    String value();

}

3、组合注解的使用与普通注解的使用是一样的

@AnnoB("B")
public class TestBean {
}

通过反射解析组合注解

既然组合注解的使用与普通注解是一样的,那是否也可以像解析普通注解一样通过反射解析组合注解呢?

public class AnnotationTest {

    public static void main(String[] args) throws Exception {
        Annotation[] annotations = TestBean.class.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
    }

}

输出结果如下,可以看到通过反射只能获取到当前类上的那个注解 AnnoB,而并不能获取到注解上的注解 AnnoA

@test.annotation.AnnoB(value=B)

如果获取不到组合注解中所有的注解,那岂不是就失去了组合的威力?JDK 的原生 API 确实不能直接获取到注解上的注解,但是通过注解然后再去获取注解还是可以完整地获取组合中所有的注解的,只是过程曲折一点。

需要注意的是:必须使用 annotationType() 方法获取 annotation 的类型才能解析注解,通过 getClass() 方法获取类型是解析不了的。

public class AnnotationTest {

    public static void main(String[] args) throws Exception {
        Annotation[] annotations = TestBean.class.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
            System.out.println("-----------");
            Arrays.stream(annotation.annotationType().getAnnotations())
                    .forEach(System.out::println);
        }
    }

}

输出如下,可以看出不光输出的组合的注解,还把其它几个 JDK 自带的元注解也都解析出来了,所以如果自己写工具类去处理组合注解的话,还得把这几个元注解过滤一下。

@test.annotation.AnnoB(value=B)
-----------
@java.lang.annotation.Target(value=[TYPE])
@java.lang.annotation.Retention(value=RUNTIME)
@java.lang.annotation.Documented()
@java.lang.annotation.Inherited()
@test.annotation.AnnoA(value=A)

使用 Spring 提供的工具类解析组合注解

Springspring-core 中的 org.springframework.core.annotation 包提供了大量关于注解的工具类。使用其中的 AnnotatedElementUtils 工具类就可以方便地获取组合注解中的每一个注解。

public class AnnotationTest {

    public static void main(String[] args) throws Exception {
        AnnoA annotationA = AnnotatedElementUtils.getMergedAnnotation(TestBean.class, AnnoA.class);
        System.out.println(annotationA);

        AnnoB annotationB = AnnotatedElementUtils.getMergedAnnotation(TestBean.class, AnnoB.class);
        System.out.println(annotationB);
    }

}

对于 Spring 工具类的使用,本文点到即止,后续会单独介绍如何使用及源码分析。