@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::getAnnotation,AnnotatedElementUtils::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();
}