springboot 注解中@AliaFor的原理:

    1. @Retention(RetentionPolicy.RUNTIME)
    2. @Target(ElementType.METHOD)
    3. @Documented
    4. public @interface AliasFor {
    5. //作用就是给AliasFor注解的value属性起了一个别名叫做attribute,那么调用的时候调用 @AliasFor(attribute='123')那么value属性的值就是123
    6. @AliasFor("attribute")
    7. String value() default "";
    8. //作用就是给AliasFor注解的attribute属性起了一个别名叫做value,那么调用的时候调用 @AliasFor(value='123')那么attribute属性的值就是123
    9. @AliasFor("value")
    10. String attribute() default "";
    11. //元注解:默认是Annotation,作用是标明别名指向的是那个注解,在使用的时候如果不指定annotation的类型的话,默认使用元注解的类型就是Annotation
    12. Class<? extends Annotation> annotation() default Annotation.class;
    13. }

    1.在同一个注解中为同一个功能定义两个名称不一样的属性,那么这两个属性彼此互为别名
    比如:@RequestMapping注解中的value和path它们两互为别名。

    1. @Target({ElementType.METHOD, ElementType.TYPE})
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Mapping
    5. public @interface RequestMapping {
    6. String name() default "";
    7. @AliasFor("path")
    8. String[] value() default {};
    9. @AliasFor("value")
    10. String[] path() default {};
    11. RequestMethod[] method() default {};
    12. String[] params() default {};
    13. String[] headers() default {};
    14. String[] consumes() default {};
    15. String[] produces() default {};

    验证代码:

    1. //定义注解
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Target(ElementType.METHOD)
    4. public @interface MyAliasAnnotation {
    5. @AliasFor(value = "location")
    6. String value() default "";
    7. @AliasFor(value = "value")
    8. String location() default "";
    9. }
    10. //编写测试类
    11. public class MyClass {
    12. @MyAliasAnnotation(location = "这是值")
    13. public static void one(){
    14. }
    15. @MyAliasAnnotation(value = "这是值")
    16. public static void one2(){
    17. }
    18. }
    19. //编写测试代码
    20. public class MyClassTest {
    21. @Test
    22. public void test1() throws NoSuchMethodException {
    23. Consumer<MyAliasAnnotation> logic = a -> {
    24. Assert.assertTrue("", "这是值".equals(a.value()));
    25. Assert.assertTrue("", a.value().equals(a.location()));
    26. };
    27. MyAliasAnnotation aliasAnnotation = AnnotationUtils.findAnnotation(MyClass.class.getMethod("one"), MyAliasAnnotation.class);
    28. logic.accept(aliasAnnotation);
    29. MyAliasAnnotation aliasAnnotation2 = AnnotationUtils.findAnnotation(MyClass.class.getMethod("one2"), MyAliasAnnotation.class);
    30. logic.accept(aliasAnnotation2);
    31. }
    32. }

    因为两个属性互为别名,所以在value没有赋值的情况下,通过AnnotationUtils仍然可以获取到值,而通过java原生的方式则无法获取。
    Spring其实是自己实现了jdk动态的拦截器来实现别名功能.


    1.把多个元注解的属性组合在一起形成新的注解
    比如:在springboot启动类注解中,他就继承了EnableAutoConfiguration注解的exclude、excludeName属性,和ComponentScan的scanBasePackages、basePackageClasses属性

    1. @Target(ElementType.TYPE)
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Documented
    4. @Inherited
    5. @SpringBootConfiguration
    6. @EnableAutoConfiguration
    7. @ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    8. @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
    9. public @interface SpringBootApplication {
    10. /**
    11. * Exclude specific auto-configuration classes such that they will never be applied.
    12. * @return the classes to exclude
    13. */
    14. @AliasFor(annotation = EnableAutoConfiguration.class)
    15. Class<?>[] exclude() default {};
    16. @AliasFor(annotation = EnableAutoConfiguration.class)
    17. String[] excludeName() default {};
    18. @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    19. String[] scanBasePackages() default {};
    20. @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    21. Class<?>[] scanBasePackageClasses() default {};
    22. @AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
    23. Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    24. @AliasFor(annotation = Configuration.class)
    25. boolean proxyBeanMethods() default true;
    26. }

    继承注解的功能

    1. 比如:如@Controller,@Service,@Repository都继承了@Component的功能,他们的基本作用和@Component完全一样都是标明某个类是Spring的Bean,需要Spring容器进行管理。
    2. 不同之处在于对Spring bean进行了归类,从而能对不同类型的Bean进行不同的处理。 ```java @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service {

      /**

      • The value may indicate a suggestion for a logical component name,
      • to be turned into a Spring bean in case of an autodetected component.
      • @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default “”;

    }

    1. 根据@AliasFor的使用形式我们可以将它分为三类
    2. ```java
    3. // 1.注解内部的显性别名
    4. public @interface ContextConfiguration {
    5. @AliasFor("locations")
    6. String[] value() default {};
    7. @AliasFor("value")
    8. String[] locations() default {};
    9. }
    10. //2.用于元注解属性的显性别名
    11. @ContextConfiguration
    12. public @interface MyTestConfig {
    13. //如案例所示,xmlFiles()指向元注解ContextConfiguration的locations属性,相当于给元注解的locations属性在当前注解中做了一个映射,
    14. //使用@MyTestConfig(xmlFiles='123')和使用@ContextConfiguration(locations='123')效果一样
    15. @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    16. String[] xmlFiles();
    17. }
    18. // 3.注解中的隐性别名(包括注解中的可传递隐性别名)
    19. @ContextConfiguration
    20. public @interface MyTestConfig {
    21. //如案例所示,value()、groovyScripts()、xmlFiles()都是指向元注解ContextConfiguration的locations属性,
    22. // 所以他们的作用一样互为隐形别名
    23. @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    24. String[] value() default {};
    25. @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    26. String[] groovyScripts() default {};
    27. @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    28. String[] xmlFiles() default {};
    29. }
    30. public @interface GroovyOrXmlTestConfig {
    31. //如案例所示,groovy()、xml()分别指向元注解MyTestConfig的groovyScripts属性和元注解ContextConfiguration的locations属性
    32. //因为元注解MyTestConfig的groovyScripts属性指向元注解ContextConfiguration的locations属性,所以groovy和xml互为可传递隐性别名
    33. @AliasFor(annotation = MyTestConfig.class, attribute = "groovyScripts")
    34. String[] groovy() default {};
    35. @AliasFor(annotation = ContextConfiguration.class, attribute = "locations")
    36. String[] xml() default {};
    37. }

    实现原理代码:

    https://zhuanlan.zhihu.com/p/368051918