注解继承与合并

注解继承:

1.被@Inherited元注解标注的注解标注在类上的时候,子类可以继承父类上的注解。
2.注解未被@Inherited元注解标注的,该注解标注在类上时,子类不会继承父类上标注的注解。
3.注解标注在接口上,其子类及子接口都不会继承该注解。
4.注解标注在类或接口方法上,其子类重写该方法不会继承父类或接口中方法上标记的注解。

注解继承分为两种情况:

  • 类级别 Type (Class, Interface)
  • 属性和方法级别 (Property, Method)

类级别 (Type): 注解 仅 在 类 Class 上且注解上含有 元注解 @Inherited 时, 才会被继承;(在 jdk 8 中, 接口Interface 无法继承任何Type类型注解)

属性和方法级别 (Property, Method): 注解无论何时都会被子类或子接口继承, 除非子类或子接口重写.

注解合并:

注解合并的含义:

合并注解就好比@RestController = @Controller + @ResponseBody,这就是 @AliasFor 的功劳。需要注意的是,离开 Spring 就无法使用了。

@AliasFor 有四个作用:
注释中的显式别名:
1
2
3
4
5
6
7
8
9
public @interface ContextConfiguration {

@AliasFor("locations")
String[] value() default {};

@AliasFor("value")
String[] locations() default {};
}

在@ContextConfiguration中, value和locations是彼此的显式别名。

元注释中属性的显式别名:
1
2
3
4
5
6
7
@ContextConfiguration
public @interface XmlTestConfig {

@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles();
}

在@XmlTestConfig中, xmlFiles是@ContextConfiguration中locations的显式别名。换句话说, xmlFiles覆盖了@ContextConfiguration中的locations属性。

注释中的隐式别名:
1
2
3
4
5
6
7
8
9
10
11
12
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] value() default {};

@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] groovyScripts() default {};

@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles() default {};
}

在@MyTestConfig中, value 、 groovyScripts和xmlFiles都是@ContextConfiguration中locations属性的显式元注释属性覆盖。因此,这三个属性也是彼此的隐式别名。

注释中的传递隐式别名:
1
2
3
4
5
6
7
8
9
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};

@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}

@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = “groovyScripts”)
String[] groovy() default {};

@AliasFor(annotation = ContextConfiguration.class, attribute = “locations”)
String[] xml() default {};
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package com.sonic.annotation.combine;

import org.springframework.core.annotation.AliasFor;
import org.springframework.core.annotation.AnnotatedElementUtils;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;


public class SynthesizedAnnotationTest {

@Target({ANNOTATION_TYPE, FIELD, TYPE})
@Retention(RUNTIME)
@interface Test1 {
String test1() default "test1";
}

@Target({ANNOTATION_TYPE, FIELD, TYPE})
@Retention(RUNTIME)
@interface Test2 {
String test2() default "test2";
}

@Target({ANNOTATION_TYPE, FIELD, TYPE})
@Retention(RUNTIME)
@Test2
@interface Test3 {
String test3() default "test3";
}

@Target({ANNOTATION_TYPE, FIELD, TYPE})
@Retention(RUNTIME)
@Test2
@interface Test4 {
/**
* AliasFor注解用来表示要覆盖Test2注解中的test2()属性方法,
* annotation属性声明的注解类必须存在于该注解的元注解上
* attribute属性声明的值必须存在于Test2注解属性方法中(即Test2注解的test2方法)
*/
@AliasFor(annotation = Test2.class, attribute = "test2")
String test4() default "test4";
}

/**
* 只有@Test4注解,但是Test4注解上组合了@Test2注解,故就可以通过Spring的工具类获取到Test2注解的内容,详见main方法
* 当然也可以将组合注解作用于更高层次,如Test3组合Test2,Test2组合Test1,然后将Test3作用于元素,通过工具类获取Test1注解功能
*/
@Test4
static class Element {
}

@Test3
static class Element1 {
}

public static void main(String[] args) {
{
Test2 test2 = AnnotatedElementUtils.getMergedAnnotation(Element.class, Test2.class);
// 虽然调用了Test2注解的test2方法,但是实际显示的是Test3注解中的test3属性声明的值
// 则说明Test2的test2属性被覆盖了
System.out.println(test2.test2());// out '覆盖Test2属性中的test2方法'
}
{
Test2 test2 = AnnotatedElementUtils.getMergedAnnotation(Element1.class, Test2.class);
System.out.println(test2);// 输出'@com.sonic.annotation.combine.SynthesizedAnnotationTest$Test2(test2=test2)'
}
}
}


参考链接:

https://blog.csdn.net/agonie201218/article/details/125105295

https://blog.csdn.net/mayfly_hml/article/details/91070465