首先 来看下SpringBoot的启动类上注解 @SpringBootApplication
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
Class>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class)
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class>[] scanBasePackageClasses() default {};
}
我们可以看到在SpringBootApplication 定义中又含有配置相关的注解:EnableAutoConfiguration。
Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
从EnableAutoConfiguration 注解定义中我们不难发现,它导入了一个AutoConfigurationImportSelector。AutoConfigurationImportSelector就是自动装配的主题,接下来来看下AutoConfigurationImportSelector的相关代码,看看他是怎么干活的?
源码如下:
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 这个是关键,获取候选的配置
List configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
跟踪:getCandidateConfigurations 方法:
protected List getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// 关键代码: 获取候选配置
List 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;
}
接着跟踪 SpringFactory.loadFactoryNames:
public static List loadFactoryNames(Class> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// 重点关注
Enumeration 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);
for (Map.Entry, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
从源码中 我们可以看到 他构建了一个资源路径,然后去这个路径下去获取属性值(需要自动装配的类);我们来看下资源路径地址:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
定位到相应的路径下:
就这样就找到了org.springframework.boot.autoconfigure.EnableAutoConfiguration 对应的属性(配置类的全路径名),进行包装然后加入IOC,完成自动配置;
自动装配时机:
refreshContext
refresh(context)
invokeBeanFactoryPostProcessors(beanFactory);
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
postProcessor.postProcessBeanDefinitionRegistry(registry);
processConfigBeanDefinitions(registry)
parser.parse(candidates);
deferredImportSelectorHandler.process()
handler.processGroupImports()
group.selectImports()
group.process
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata)
.