SpringBootApplication注解解析
写在前面
本文主要用于记录自己学习SpringBoot源码过程中的收获,不一定准确,仅供参考。
SpringBootApplication注解简介
@SpringBootApplication注解是一个复合注解,主要是由 @SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解组合而成。
SpringBootConfiguration注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
从源码可以看出,该注解主要是引用 @Configuration 注解,将其作为配置类注入。
EnableAutoConfiguration注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
/**
* Exclude specific auto-configuration classes such that they will never be applied.
* @return the classes to exclude
*/
Class<?>[] exclude() default {};
/**
* Exclude specific auto-configuration class names such that they will never be
* applied.
* @return the class names to exclude
* @since 1.3.0
*/
String[] excludeName() default {};
}
同样从源码可以看出,该注解主要是由两部分来实现,其一是通过 @Import 注解引入 AutoConfigurationImportSelector 类,其二是引入注解 @AutoConfigurationPackage。
AutoConfigurationImportSelector
这一部分内容主要是自动导入的一些原理,简要来说,该类实现了 ImportSelector 接口,在项目启动的过程中,会自动调用其 selectImports方法,选择出需要自动导入的类,其过程比较重要,详细分析过程可以见博客~(SpringBoot自动注入分析)。
AutoConfigurationPackage
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
}
该注解主要是通过 @Import 注解引入 Registrar 类,该类是 AutoConfigurationPackages
的静态内部类,核心方法如下:
static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
register(registry, new PackageImport(metadata).getPackageName());
}
@Override
public Set<Object> determineImports(AnnotationMetadata metadata) {
return Collections.singleton(new PackageImport(metadata));
}
}
其实 Registrar 的作用没有想象中的那么难以理解,因为我们想要导入类,一个一个使用 import 的话就很慢,这里 registerBeanDefinitions 方法其实就是批量注册。
AnnotationMetadata 这个代表的是注解元数据,怎么理解呢,其实就是我们当前所注解类的信息。在这里的话其实就代表 AutoConfigurationPackage 注解标在了哪、它的每一个属性值都是什
么,通过打断点可以看到这里的 metadata 所代表的的信息如下:
这里的class显示的是主程序启动类的信息,因为我们注解是依次往下分析的,最初的注解还是 @SpringBootApplication,所以标记的类为启动类。
register(registry, new PackageImport(metadata).getPackageName());
registerBeanDefinitions 方法主要还是调用的 register 方法,入参除了 registry 之外,还有新建了一个对象为 PackageImport 。它也是 AutoConfigurationPackages 类的静态内部类,入参是我们的 metadata, 最终获取到包名,给予 register 方法的入参也包名,也就是我们启动类的包名,相当于把我们整个包里面的内容都要做注册操作。这里我们也可以理解,为什么我们要把启动类放到包的最外层。
ComponentScan注解
ComponentScan 做的事情就是告诉Spring从哪里找到bean,可以指定去扫描那些包、排除那些包,这里默认就会扫描我们main方法所在的包及其下级包。