术语
Meta-Annotations元注解
元注解用于声明在其他注解上,作为注解的注解。相反的角度来说,如果一个注解被元注解标注。例如:
@Service is meta-annotated with @Component
Stereotype Annotations 模式注解
模式注解用来声明一个组件在应用中扮演的角色。比如@Repository 用来表示当前组件时一个数据库层。
@Component是一个通用的模式注解用来表示spring管理的组件。@Component标注的组件会被组件扫描器扫描并且加载到容器中。
@Component, @Service, @Repository, @Controller, @RestController, @Configuration. @Repository, @Service, 等等. 都是被 @Component标注的
Composed Annotations 派生注解
派生注解是被一个或者多个元注解标注的,同时具备多个元注解特性的注解。
Annotation Presence 注解的层次表现
如果一个注解被其他元注解标注过,该注解自动获得该元注解的特性,类似集成的特性。
- @Component
- @Repository
- FirstLevelRepository
- SecondLevelRepository
- FirstLevelRepository
- @Repository
SecondLevelRepository继承自元注解@Component,他也具备其特性。被@SecondLevelRepository标注的注解,也是ComponentScan的扫描和加载的对象。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repository
public @interface FirstLevelRepository {
String value() default "";
}
/**
* 层次性:一级的注解可以用来标注二级注解
* 派生性: 每层注解集成上级注解的特性
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@FirstLevelRepository
public @interface SecondLevelRepository {
String value() default "";
}
Attribute Aliases and Overrides 属性别名和覆盖
属性别名
属性别名是通过 @AliasFor标注在属性上,表示两个属性是可以交换使用,并且是等价的。
- 显示别名,一个注解中的两个成员通过 @AliasFor声明后互为别名,那么它们是显式别名
- 隐式别名,一个注解中的两个或者更多成员通过@AliasFor声明去覆盖同一个元注解的成员值,它们就是隐式别名
- 传递性隐式别名,如果一个注解中的两个或者更多成员通过@AliasFor声明去覆盖元注解中的不同成员,但是实际上因为覆盖的传递性导致最终覆盖的是元注解中的同一个成员,那么它们就是传递隐式别名。
属性覆盖
属性覆盖指的是注解的一个成员覆盖另一个成员,最后两者成员属性值一致。
假设注解@One被元注解@Two标注
-
隐式覆盖(Implicit Overrides),如果属性A在@ONE和TWO中都存在则
-
显示覆盖(Explicit Overrides),如果@ONE中有一个属性A显示@AliasFor声明是@TWO的B的别名
-
传递式显式覆盖(Transitive Explicit Overrides),如果注解 @One#name 显示覆盖了 @Two#nameAlias,而 @Two#nameAlias显示覆盖了 @Three#nameAlias,最后因为传递性,@One#name 实际覆盖了@Three#nameAlias。
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
使用时下面三种方式是等价的
@ContextConfiguration("/test-config.xml")
public class MyTests { /* ... */ }
@ContextConfiguration(value = "/test-config.xml")
public class MyTests { /* ... */ }
@ContextConfiguration(locations = "/test-config.xml")
public class MyTests { /* ... */ }
可以通过下面方式精确覆盖元注解的属性
这里子注解的xmlFiles属性覆盖了元注解的value属性
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "value")
String[] xmlFiles();
// ...
}
spring本身利用注解别名和覆盖的特性
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(method = RequestMethod.GET)
public @interface GetMapping {
/**
* Alias for {@link RequestMapping#name}.
*/
@AliasFor(annotation = RequestMapping.class)
String name() default "";
/**
* Alias for {@link RequestMapping#value}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] value() default {};
/**
* Alias for {@link RequestMapping#path}.
*/
@AliasFor(annotation = RequestMapping.class)
String[] path() default {};
// ...
}