@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}
)}
)
前三个的作用分别是:
@Target({ElementType.TYPE, ElementType.METHOD})--》可以修饰在类与方法上
@Retention(RetentionPolicy.RUNTIME)--》注解生效节点runtime
@Documented--》生成文档
然后是@SpringBootConfiguration:其实就是@Configuration,标注在哪就说明这是一个SpringBoot配置类,用来配置bean,所以有了这个注解之后我们可以在SpringBoot运行的主类中使用@Bean标签配置类了。
但是并不是所有的bean都会被初始化 ,在配置类中使用Condition来加载满足条件的bean;
在springBoot-autoconfigure的condition包下
1.ConditionalOnProperty:判断配置文件中是否有对应属性和值才初始化Bean.
2.ConditionalOnClass:判断环境中是否有对应字节码文件才初始化Bean
3.ConditionalOnMissingBean:判断环境中没有对应Bean才初始化Bean
4.ConditionalOnBean:判断环境中有对应Bean才初始化Bean
@ComponentScan:组件扫描,扫描SpringBoot主启动类的同级路径及子路径,将这个bean定义加载到IOC容器中。
@EnableAutoConfiguration:开启自动配置功能,有了这个注解,就会告诉SpringBoot开启自动配置功能
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自动配置包,将主配置类(@SpringBootApplication标注的类)的所在包及下面所有的子包里面的所有组件扫描到Spring容器中。
@Import注解:导入的类会被加载到IOC容器中,实现bean的动态加载,有四种用法
1.导入bean
2.导入配置类
3.导入ImportSelector实现类。一般用于加载配置文件中的类
4.导入ImportBeanDefinitionRegistrar实现类
其中@Import({AutoConfigurationImportSelector.class})这个注解是给容器导入组件
AutoConfigurationImportSelector:自动配置导入选择器,给容器导入一些组件
然后进入
protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!this.isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
} else {
AnnotationAttributes attributes = this.getAttributes(annotationMetadata);
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
configurations = this.removeDuplicates(configurations);
Set exclusions = this.getExclusions(annotationMetadata, attributes);
this.checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = this.getConfigurationClassFilter().filter(configurations);
this.fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
}
}
通过getCandidateConfigurations()得到候选配置类
protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}
然后加载这些META-INF/spring.factories文件,通过文件名获取每个配置类的url,再通过这些url将他们封装成Properties对象,最后解析内容存在map
private static Map> loadSpringFactories(ClassLoader classLoader) {
Map> result = (Map)cache.get(classLoader);
if (result != null) {
return result;
} else {
HashMap result = new HashMap();
try {
Enumeration urls = classLoader.getResources("META-INF/spring.factories");
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
Iterator var6 = properties.entrySet().iterator();
while(var6.hasNext()) {
Entry, ?> entry = (Entry)var6.next();
String factoryTypeName = ((String)entry.getKey()).trim();
String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
String[] var10 = factoryImplementationNames;
int var11 = factoryImplementationNames.length;
for(int var12 = 0; var12 < var11; ++var12) {
String factoryImplementationName = var10[var12];
((List)result.computeIfAbsent(factoryTypeName, (key) -> {
return new ArrayList();
})).add(factoryImplementationName.trim());
}
}
}
result.replaceAll((factoryType, implementations) -> {
return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
});
cache.put(classLoader, result);
return result;
} catch (IOException var14) {
throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
}
}
}
最终,getCandidateConfigurations()方法获取到了候选配置类并存于List中。之所以说是“候选”,是因为它们后续还需要经过一系列的去重、排除、过滤等操作,通过selectImports()方法返回一个自动配置类的全限定名数组,然后将所有自动配置类加载到Spring容器中,当SpringBoot容器启动时会自动加载配置类,初始化bean。这样就实现了自动装配。