1、剖析@SpringBootApplication注解
创建一个SpringBoot工程后,SpringBoot会为用户提供一个Application类,该类负责项目的启动:
@SpringBootApplication
public class SpringbootSeniorApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootSeniorApplication.class, args);
}
}
这是一个被@SpringBootApplication
注解的类,该注解完成了SpringBoot中类的自动装配任务:
@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 {
...
}
抛却元注解不谈,@SpringBootApplication继承了三个注解:
- @SpringBootConfiguration
在说明中提到,/** * Indicates that a class provides Spring Boot application * {@link Configuration @Configuration}. Can be used as an * alternative to the Spring's standard @Configuration * annotation so that configuration can be found * automatically (for example in tests). * * Application should only ever include one * @SpringBootConfiguration and most idiomatic Spring Boot * applications will inherit it from @SpringBootApplication. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { ... }
@SpringBootConfiguration
注解是用来替代Spring的@Configuration
,方便SpringBoot自动找到配置。 - @ComponentScan
在说明中我们可以得知:/** * Configures component scanning directives * for use with Configuration classes. * Provides support parallel with Spring XML's * <context:component-scan> element. * * Either #basePackageClasses or #basePackages * (or its alias #value} may be specified to * define specific packages to scan. If specific * packages are not defined, scanning will occur * from the package of the class that declares * this annotation. * * Note that the <context:component-scan> element * has an annotation-config attribute; however, * this annotation does not. This is because * in almost all cases when using @ComponentScan, * default annotation config processing * (e.g. processing @Autowired and friends) * is assumed. Furthermore, when using * AnnotationConfigApplicationContext, * annotation config processors are always * registered, meaning that any attempt to disable * them at the @ComponentScan level would be ignored. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Documented @Repeatable(ComponentScans.class) public @interface ComponentScan { ... }
@ComponentScan
只负责指定要扫描的包,并没有装配其中的类,这个真正装配这些类是@EnableAutoConfiguration
。 - @EnableAutoConfiguration
该类真正完成了SpringBoot对于类的装配工作,具体内容在后续会作出解释。@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
2、以@Enable开头的注解
以@Enable开头的注解(@EnableXxx
)一般用于开启某一项功能,是为了简化代码的导入。它是一个组合注解,一般情况下@EnableXxx
注解中都会组合一个@Import
注解,而该@Import
注解用于导入指定的类,而被导入的类一般有三种:
2.1、配置类
- 类的特征:@Import中指定的类一般以Configuration结尾
- 类的配置:该类上会注解@Configuration
- 类的案例:定时任务启动注解:
SchedulingConfiguration
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }
2.2、选择器
- 类的特征:@Import中指定的类一般以 Selector 结尾
- 类的配置:该类直接或间接实现了
ImportSelector
接口,表示当前类会根据条件选择导入不同的类。 - 类的案例:Redis配置类:
CachingConfigurationSelector
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(CachingConfigurationSelector.class) public @interface EnableCaching { ... }
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> { ... @Override public String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return getProxyImports(); case ASPECTJ: return getAspectJImports(); default: return null; } } ... }
2.3、注册器
- 类的特征:@Import 中指定的类一般以 Registrar 结尾。
- 类的配置:该类直接或间接实现了
ImportBeanDefinitionRegistrar
接口,用于导入注册器,该类可以在代码运行时动态注册指定类的实例。 - 类的案例:AspectJ:
AspectJAutoProxyRegistrar
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AspectJAutoProxyRegistrar.class) public @interface EnableAspectJAutoProxy