springboot注解–基础–04–注解合并,继承
1、注解的继承
1.1、注解分为两种情况
- 类级别 Type(Class,Interface)
- 注解仅在 类Class上,且注解上 含有元注解 @Inherited 时,才会被继承
- 在 jdk 8 中,接口Interface无法继承任何Type类型注解
- 属性和方法级别(Property,Method)
- 注解无论何时都会被子类或子接口继承,除非子类或子接口重写
1.2、测试
public class IterInheritedTest {
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotationType {}
@Inherited
@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ABC {
String value() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface UnInheritedAnnotationType {}
@UnInheritedAnnotationType
static
class A {}
@InheritedAnnotationType
static
class B extends A {}
static class C extends B {}
@UnInheritedAnnotationType
interface Z {
@ABC()
void he();
}
@InheritedAnnotationType
interface Y extends Z {
@ABC("hhhh")
void he();
}
interface X extends Y {}
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
System.out.println(X.class.getAnnotation(InheritedAnnotationType.class));
System.out.println(Y.class.getAnnotation(InheritedAnnotationType.class));
System.out.println(Z.class.getAnnotation(InheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(X.class.getAnnotation(UnInheritedAnnotationType.class));
System.out.println(Y.class.getAnnotation(UnInheritedAnnotationType.class));
System.out.println(Z.class.getAnnotation(UnInheritedAnnotationType.class));
System.out.println("_________________________________");
System.out.println(Arrays.toString(Z.class.getMethod("he").getAnnotations()));
System.out.println(Arrays.toString(Y.class.getMethod("he").getAnnotations()));
System.out.println(Arrays.toString(X.class.getMethod("he").getAnnotations()));
}
}
输错
null
@org.pzone.crypto.IterInheritedTest$InheritedAnnotationType()
null
_________________________________
null
null
@org.pzone.crypto.IterInheritedTest$UnInheritedAnnotationType()
_________________________________
[@org.pzone.crypto.IterInheritedTest$ABC(value=)]
[@org.pzone.crypto.IterInheritedTest$ABC(value=hhhh)]
[@org.pzone.crypto.IterInheritedTest$ABC(value=hhhh)]
2、注解的合并
2.1、合并的含义
- 注解只在springboot中有用
- 注解本身并不能被注解继承
- 注解合并需要使用:@AliasFor
2.2、合并注解的案例
@RestController = @Controller + @ResponseBody
通过 @AliasFor来完成
2.3、@AliasFor 的4个作用
2.3.1、注释中的显式别名
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value()default {};
@AliasFor("value")
String[] locations()default {};
}
在@ContextConfiguration中, value和locations是彼此的显式别名。
2.3.2、元注释中属性的显式别名
@ContextConfiguration
public @interface XmlTestConfig {
# xmlFiles覆盖了@ContextConfiguration中的locations属性。
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xmlFiles();
}
在@XmlTestConfig中,xmlFiles是@ContextConfiguration中locations的显式别名。
2.3.3、注释中的隐式别名
@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属性。
- value、groovyScripts、xmlFiles 属性也是彼此的隐式别名。
2.3.4、注释中的传递隐式别名
@MyTestConfig
public @interface GroovyOrXmlTestConfig {
@AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
String[] groovy() default {};
@AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
String[] xml() default {};
}
- groovy 显式覆盖 @MyTestConfig中 groovyScripts属性
- xml 显式覆盖 @ContextConfiguration中 locations 属性。
- groovy 和 xml 是彼此的可传递隐式别名,因为它们都有效地覆盖了 @ContextConfiguration 中的 locations 属性。
2.4、案例
把多个注解合并成1个,这里把@RestController和@RequestMapping合并为一个@PathRestController
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
@RequestMapping
public @interface PathRestController {
@AliasFor("path")
String[] value()default {};
@AliasFor("value")
String[] path()default {};
}