前言
SpringBoot启动流程源码分析第一篇之 @SpringBootApplication 注解到底做了什么?
本篇使用SpringBoot 2.3.0.RELEASE
版本,试图理清楚SpringBoot启动时到底做了什么,这是第一篇,先搞清楚@SpringBootApplication
做了什么。鬼知道SpringBoot会牵扯出来多少坑。
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| @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(annotation = ComponentScan.class, attribute = "nameGenerator") Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class; @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
|
解释
@SpringBootApplication
是个组合注解(composed annotation),用它就相当于同时用了下面三个注解:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
所以如果在启动类上加入这三个注解,也可以替代@SpringBootApplication
注解,组合注解主要用来简化代码。
@ComponentScan
注解
这个注解很熟悉了,SpringMVC就开始用了,无非就是自动扫描并加载符合条件的Bean到容器中,这个注解会默认扫描声明类所在的包开始扫描。
例如:类cn.shiyujun.Demo类上标注了@ComponentScan 注解,则cn.shiyujun.controller、cn.shiyujun.service等等包下的类都可以被扫描到
这个注解一共包含以下几个属性:
- basePackages:指定多个包名进行扫描
- basePackageClasses:对指定的类和接口所属的包进行扫
- excludeFilters:指定不扫描的过滤器
- includeFilters:指定扫描的过滤器
- lazyInit:是否对注册扫描的bean设置为懒加载
- nameGenerator:为扫描到的bean自动命名
- resourcePattern:控制可用于扫描的类文件
- scopedProxy:指定代理是否应该被扫描
- scopeResolver:指定扫描bean的范围
- useDefaultFilters:是否开启对@Component,@Repository,@Service,@Controller的类进行检测
@SpringBootConfiguration
注解
1 2 3 4 5 6 7 8
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Configuration public @interface SpringBootConfiguration { @AliasFor(annotation = Configuration.class) boolean proxyBeanMethods() default true; }
|
这个注解只是将@Configuration 注解封装起来而已,并没有做其他操作。注:Configuration相当于原来的xml配置,用于配置Bean。
@EnableAutoConfiguration
注解
才是重头戏,主要功效就是利用@Import
注解( @Import
注解详情看这里),将所有符合自动装配条件的Bean
注入到IOC
容器中。下面来看一下源码。
1 2 3 4 5 6 7 8 9
| @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @AutoConfigurationPackage @Import(AutoConfigurationImportSelector.class) public @interface EnableAutoConfiguration { ... }
|
这里使用@Import
注解引用AutoConfigurationImportSelector
类,下面看一下AutoConfigurationImportSelector
源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered { ... 这里省略了很多非关键代码 @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return NO_IMPORTS; } AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata); return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations()); } protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) { if (!isEnabled(annotationMetadata)) { return EMPTY_ENTRY; } AnnotationAttributes attributes = getAttributes(annotationMetadata); List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); configurations = removeDuplicates(configurations); Set<String> exclusions = getExclusions(annotationMetadata, attributes); checkExcludedClasses(configurations, exclusions); configurations.removeAll(exclusions); configurations = getConfigurationClassFilter().filter(configurations); fireAutoConfigurationImportEvents(configurations, exclusions); return new AutoConfigurationEntry(configurations, exclusions); } protected boolean isEnabled(AnnotationMetadata metadata) { if (getClass() == AutoConfigurationImportSelector.class) { return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true); } return true; } ....
|
总结
@SpringBootApplication
是一个组合注解,分别组合了@EnableAutoConfiguration
(开启自动装配) @ComponentSacn
(指定默认扫描包为注解类的当前目录)@Configuration
标注注解类