元注解用于声明在其他注解上,作为注解的注解。相反的角度来说,如果一个注解被元注解标注。例如:
@Service is meta-annotated with @Component
模式注解用来声明一个组件在应用中扮演的角色。比如@Repository 用来表示当前组件时一个数据库层。
@Component是一个通用的模式注解用来表示spring管理的组件。@Component标注的组件会被组件扫描器扫描并且加载到容器中。
@Component, @Service, @Repository, @Controller, @RestController, @Configuration. @Repository, @Service, 等等. 都是被 @Component标注的
派生注解是被一个或者多个元注解标注的,同时具备多个元注解特性的注解。
如果一个注解被其他元注解标注过,该注解自动获得该元注解的特性,类似集成的特性。
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 "";
}
属性别名是通过 @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 {};
// ...
}