SpringBoot之 @AliasFor 注解

711 阅读1分钟

@SpringBootApplication

@SpringBootApplication 等于 @EnableAutoConfiguration,@ComponentScan@SpringBootConfiguration三个注解的组合,

互为别名

@ComponentScan 的value和basePackages作用是一样的。

public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    boolean lazyInit() default false;
    ...
}

有了AliasFor的好处是,如果我们只需要指定basePackages,可以使用value属性,并且可以使用默认value属性格式。 如果除了basePackages,还有其他属性,可以使用第二种方式。 将value属性换成basePackages,更明确清晰。

//方式一
@ComponentScan("com.catalina")

//方式二
@ComponentScan(basePackages = "com.catalina", lazyInit = true)

跨注解的属性别名

@Component
public @interface Service {
    @AliasFor(annotation = Component.class)
    String value() default "";
}

注解可以作用于注解。
@Service::value@Component::value的别名,@Service::value的值可以映射到@Component::value。 (这里我们将@Service@Component看做一种特殊的继承关系,@Component父注解@Service是子注解,@Service::value覆盖@Component::value

static <A extends Annotation> A synthesizeAnnotation(A annotation, @Nullable Object annotatedElement) {
    ...

    DefaultAnnotationAttributeExtractor attributeExtractor =
            new DefaultAnnotationAttributeExtractor(annotation, annotatedElement);
    InvocationHandler handler = new SynthesizedAnnotationInvocationHandler(attributeExtractor);

    // Can always expose Spring's SynthesizedAnnotation marker since we explicitly check for a
    // synthesizable annotation before (which needs to declare @AliasFor from the same package)
    Class<?>[] exposedInterfaces = new Class<?>[] {annotationType, SynthesizedAnnotation.class};
    return (A) Proxy.newProxyInstance(annotation.getClass().getClassLoader(), exposedInterfaces, handler);
}

Spring的AnnotationUtils::getAnnotation -> synthesizeAnnotation

SpringBootApplication

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
    @AliasFor(annotation = EnableAutoConfiguration.class)
    Class<?>[] exclude() default {};

    @AliasFor(annotation = EnableAutoConfiguration.class)
    String[] excludeName() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
    String[] scanBasePackages() default {};

    @AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
    Class<?>[] scanBasePackageClasses() default {};
}

通过@AliasFor,即使用户使用的是@SpringBootApplication, Spring还是可以通过AnnotationUtils::getAnnotationAnnotatedElementUtils::getMergedAnnotation等方法,解析到@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan等注解,并取得对应属性。

还有@Repeatable注解是jdk8新增的注解,可以将多个注解替换为一个数组注解。

@Repeatable(ComponentScans.class)
public @interface ComponentScan {
...
}

@Repeatable表示当使用了多个@ComponentScan时,多个@ComponentScan可以被@ComponentScans代替。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScans {
    ComponentScan[] value();
}