首先打开springboot启动程序入口
@SpringBootApplication
public class Springboot01Application {
//
public static void main(String[] args) {
SpringApplication.run(Springboot01Application.class, args);
}
}
@SpringBootApplication:标注了这个类是SpringBoot应用。
一、我们看下自动装配的结构分析:(点击启动类上的注解@SpringBootApplication
)
@SpringBootConfiguration :springboot的配置
----> @Configuration :spring的配置类
---> @Component :说明这也是一个spring的组件
@EnableAutoConfiguration : 自动配置
---> @AutoConfigurationPackage : 自动配置包
---> @Import(AutoConfigurationPackages.Registrar.class) :自动配置“包注册”
---> @Import(AutoConfigurationImportSelector.class) : 自动配置,导入选择
---> AutoConfigurationImportSelector 自动导入选择器,SpringBoot自动导包的核心
@ComponentScan():扫描当前主启动类同级的包(此处扫描到包,然后通过Registrar去注册)
二、自动导入选择器AutoConfigurationImportSelector 中到底具体选择了什么内容?我们来细致分析
方法:selectImports 导入核心组件(pom.xml文件中的组件)
1. selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
2. getAutoConfigurationEntry : 获得自动配置的实体
上面方法调用本类中的 getAutoConfigurationEntry()方法,通过getCandidateConfigurations ( )获取候选的配置
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);
}
3. getCandidateConfigurations
getAutoConfigurationEntry()方法内部调用 getCandidateConfigurations()方法,获取候选的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader());
// 此处的断言,如果confi
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;
}
3.1 getSpringFactoriesLoaderFactoryClass
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;//标注了EnableAutoConfiguration注解的类
}
3.2 spring.factories的文件位置:
spring-boot-autoconfigure-2.2.7.RELEASE.jar -----> META-INF -----> spring.factories:所有的自动配置类都在这里
4. getAutoConfigurationEntry()方法中调用了类SpringFactoriesLoader下的 loadFactoryNames()方法,从spring.factories获取所有的加载配置
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
String factoryTypeName = factoryType.getName(); //获取类的名字
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
// FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); //获取所有资源
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) { // 判断有没有更多的元素
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);// 所有的资源封装到Properties配置类
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryTypeName, factoryImplementationName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
5. 通过此方法,就可以获取到所有的spring.factories中的所有自动配置类,实现SpringBoot的自动装配。但是实现自动装配后,不一定能生效,需要满足@ConditionalOn***的条件。例如:
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
总结
springboot 所有的自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效。要判断条件是否成立,只要导入了对应的start,就有对应的启动器了,有了启动器,我们自动装配就会生效,然后就配置成功!