@SpringBootApplication 注解解析
使用springboot第一步都是添加@SpringBootApplication,这个注解有什么作用呢?!
看@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 {
......
}
看源码可以看出 主要的注解有三个
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
首先@SpringBootConfiguration这个注解:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
......
}
可以看出@SpringBootConfiguration就是@Configuration注解的再套一层,本质上还是@Configuration,而@Configuration注解的作用就是javaConfig形式的配置类,用于spring ioc容器,springbooot使用@Configuration,说明这也是springboot ioc容器的配置类。
其次@ComponentScan注解定义包扫描范围,所以启动类最后放在root package路径下。
最后最关键的注解@EnableAutoConfiguration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
......
}
从代码看出,这个注解通用@Import(…)这个注解来自动注入配置而其中AutoConfigurationImportSelector.class这个类就是springboot自动话配置的关键
先看图:
从这个图可以看出,@EnableAutoConfiguration类似八爪鱼一样,把所有的配置给集合到一起。
看AutoConfigurationImportSelector.class的源码:
首先看selectImports方法
AutoConfigurationImportSelector实现ImportSelector接口的selectImports,selectImports这个方法会放回一组路径,spring启动的时候会自动注入路径的配置类。大致在spring的ConfigurationClassParser$DeferredImportSelectorGroupingHandler类中的processImports()方法实现的。
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 获取自动化配置元数据
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
// 获取自动化配置列表(*)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
// 返回配置类全路径名 spring会自动注入配置
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
其中的getAutoConfigurationEntry:
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
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 = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
getCandidateConfigurations:
// 调用SpringFactoriesLoader对象 获取META-INF/spring.factories下面的配置(*)
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
getSpringFactoriesLoaderFactoryClass:
// 获取EnableAutoConfiguration的class
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
可以看出,我们通过getCandidateConfigurations方法获取配置,而这个方法最终调用的是SpringFactoriesLoader.loadFactoryNames方法获取配置类,我们需要两个参数,一个是EnableAutoConfiguration的class,一个是ClassLoader
SpringFactoriesLoader.loadFactoryNames:
// 通过class名字获取获取META-INF/spring.factories
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
我们看一下META-INF/spring.factories
到这里,我们就大致知道getAutoConfigurationEntry自动化获取配置方法就是通过EnableAutoConfiguration的路径,通过SpringFactoriesLoader的loadFactoryNames方法获取自动化配置的左右类的路径列表。然后使用ImportSelector接口的selectImports方法返回需要自动配置的对象列表,然后通过spring的ConfigurationClassParser
D
e
f
e
r
r
e
d
I
m
p
o
r
t
S
e
l
e
c
t
o
r
G
r
o
u
p
i
n
g
H
a
n
d
l
e
r
类
中
的
p
r
o
c
e
s
s
I
m
p
o
r
t
s
(
)
方
法
来
自
动
注
入
所
有
需
要
自
动
化
配
置
的
类
。
C
o
n
f
i
g
u
r
a
t
i
o
n
C
l
a
s
s
P
a
r
s
e
r
DeferredImportSelectorGroupingHandler类中的processImports()方法来自动注入所有需要自动化配置的类。 ConfigurationClassParser
DeferredImportSelectorGroupingHandler类中的processImports()方法来自动注入所有需要自动化配置的类。ConfigurationClassParserDeferredImportSelectorGroupingHandler类中的processImports()方法:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 1、如果该配置类被ImportSelector修饰,则当成ImportSelector进行处理
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(
configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
// 2、如果该配置类被ImportBeanDefinitionRegistrar修饰,则当成ImportBeanDefinitionRegistrar进行处理
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
// 3、如果该配置类被Import修饰,则当成Import进行处理
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
注释源码:https://gitee.com/w849027724/spring-boot-master
链接:
https://juejin.im/post/5d63b455f265da03e52341d0
http://tengj.top/2017/03/09/springboot3/
https://www.jianshu.com/p/3da069bd865c