多年来,Spring Framework不断发展对注解、元注解和组合注解的支持。 本文档旨在帮助开发人员(Spring的最终用户以及Spring Framework和Spring组合项目的开发人员)开发和使用Spring注解。
本文档的主要目标包括以下内容的解释:
本文档的目的不是解释Spring Framework中特定注解的语义或配置选项。有关特定注解的详细信息,建议开发人员查阅对应的Javadoc或参考手册的相应部分。
元注解是在另一个注解上声明的注解。如果一个注解使用其他注解进行注解,因此,这个注解被元注解。例如,声明要记录的任何注解都是使用java.lang.annotation
包中的@Documented
进行元注解的。
构造型注解是一种注解,用于声明组件在应用程序中扮演的角色。 例如,Spring Framework中的@Repository
注解是任何满足存储库角色或构造型(也称为数据访问对象或DAO)的类的标记。
@Component
是任何Spring管理组件的通用构造型。使用@Component注解的任何组件都是作为等待被扫描的组件。类似地,任何使用@Component
进行元注解的注解,那么其注解的组件也是作为将要被扫描的组件。 例如,@Service
使用@Component
进行元注解。
Core Spring提供了几种开箱即用的构造型注解,包括但不限于:@Component
,@Service
,@Repository
,@ Controller
,@RestController
和@Configuration
。 @Repository
,@Service
等是@Component
的特化。
组合注解是使用一个或多个注解进行元注解的注解,其目的是将与这些元注解相关联的行为组合到单个自定义注解中。 例如,使用Spring的@Transactional
和@Service
注解进行元注解的名为@TransactionalService
的注解是一个组合注解,它结合了@Transactional
和@Service
的语义。@TransactionalService
在技术上也是一个自定义构造型注解。
直接存在,间接存在和存在的术语与Java 8中java.lang.reflect.AnnotatedElement
的类级别Javadoc中定义的含义相同。
在Spring中,如果注解被声明为元素上存在的其他注解上的元注解,则注解被认为是元素上的元存在。 例如,给定前面提到的@TransactionalService
,我们会说@Transactiona
l在任何直接用@TransactionalService
注解的类上都是元存在的。
一个属性别名是从一个注解属性到另一个注解属性的别名。 一组别名中的属性可以互换使用,并视为等效。 属性别名可以按如下分类:
@AliasFor
声明为彼此的别名,则它们是显式别名。@AliasFor
声明为元注解中同一属性的显式覆盖,则它们是隐式别名。@AliasFor
声明为元注解中属性的显式覆盖,如果属性有效地覆盖符合传递规律的元注解中的相同属性,则它们是传递性的 隐含别名。一个属性覆盖是一种注解属性,它覆盖(或隐藏)元注解中的注记属性。 属性覆盖可以按如下分类:
@One
中的属性A和注解@Two
中的属性A,如果@One
使用@Two
进行元注解,则注解@One
中的属性A是注解@Two
中属性A的隐式覆盖,仅基于命名约定(即两个属性都命名为A)。@AliasFor
的元注解中被声明为属性B的别名,则A是B的显式覆盖。@One
中的属性A是注解@Two
中属性B的显式覆盖,而属性B是注解@Three
中的属性C的显式样覆盖,则A是遵循传递定律的C的传递显式覆盖。Spring Framework和Spring组合项目中的许多注解都使用@AliasFor
注解来声明属性别名和属性覆盖。 常见的例子包括来自Spring MVC的@ RequestMapping
,@GetMapping
和@PostMapping
,以及来自Spring Boot的@SpringBootApplication
和@SpringBootTest
等注解。
Spring Framework 4.2引入了最好的支持,用于声明和查找注解属性的别名。 @AliasFor
注解可用于在单个注解中声明一对别名属性,或者将自定义组合注解中的一个属性的别名声明为元注解中的属性。
例如,spring-test模块的@ContextConfiguration
声明如下。
public @interface ContextConfiguration {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
// ...
}
locations
属性被声明为value
属性的别名,反之亦然。 因此,@ContextConfiguration
的以下声明是等效的。
@ContextConfiguration("/test-config.xml")
public class MyTests { /* ... */ }
@ContextConfiguration(value = "/test-config.xml")
public class MyTests { /* ... */ }
@ContextConfiguration(locations = "/test-config.xml")
public class MyTests { /* ... */ }
相似地,覆盖元注解中的属性的组合注解可以使用@AliasFor
对注解层次结构中的哪些属性进行细粒度控制。 实际上,甚至可以为元注解的value
属性声明别名。
例如,可以使用自定义属性覆盖开发组合注解,如下所示:
@ContextConfiguration
public @interface MyTestConfig {
@AliasFor(annotation = ContextConfiguration.class, attribute = "value")
String[] xmlFiles();
// ...
}
上面的示例演示了开发人员如何实现自己的自定义组合注解; 然而,以下解释Spring本身在许多核心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 {};
// ...
}
Spring Composed项目是一个用于Spring Framework 4.2.1及更高版本的组合注解的集合。 在那里你会发现@Get
,@Post
,@Put
和@Delete
等注解,它们是@GetMapping
,@PostMapping
,@PutMapping
和@DeleteMapping
注解的灵感来源,这些注解现在是Spring MVC和Spring WebFlux的一部分。
请随意参考spring-composed
项目以获得更多示例和灵感,了解如何实现自己的自定义组合注解,以及进一步展示@AliasFor
功能带来的极客幽默和娱乐,请查看Spring Polyglot。
1)@AliasFor
可以与@Component
和@Qualifier
的值属性一起使用吗?
最简洁的答案是不。
@AliasFor
不会影响@Qualifier和构造型注解中的值属性(例如@Component
,@Repository
,@Controller
和任何自定义构造型注解)。 原因是这些价值属性的特殊处理在@AliasFor
发明之前的几年就已经存在。 因此,由于向后兼容性问题,根本不可能将@AliasFor
与这些值属性一起使用。
记录关于类、接口、方法、字段、参数和注解的注解和元注解的一般搜索算法。
@Inherited
在注解(包括自定义组合注解)上的存在如何影响搜索算法?对通过@AliasFor
配置的注解属性别名的文档支持。
对组合注解的文档支持
对在组合注解中元注解属性覆盖的文档支持
@AliasFor
显式映射翻译:Evan Leung
[Spring Annotation Programming Model]https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model