docs/Spring全家桶/SpringBoot源码解析/SpringBoot自动装配(一):加载自动装配类.md
Զװ springboot ĺ֮һĽ̽ springboot μԶװġ
@SpringBootApplication עһУᵽ springboot Զװע @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 {};
}
ϴ֣
@AutoConfigurationPackageָԶװİ@Import(AutoConfigurationImportSelector.class)ԶװĴ AutoConfigurationImportSelectorԶװĹؼڣ@EnableAutoConfiguration ԣ@EnableAutoConfiguration ṩԣexclude excludeNameųҪԶװࡣص AutoConfigurationImportSelector ࡣ
AutoConfigurationImportSelector.AutoConfigurationGroupAutoConfigurationImportSelector ʵ DeferredImportSelector DeferredImportSelector ķԲο ConfigurationClassPostProcessor ֮ @Import עֱӸۣ
DeferredImportSelector ImportSelector ӽӿڣڲһӿ Groupýӿڶ
public interface DeferredImportSelector extends ImportSelector {
...
interface Group {
/**
*
*/
void process(AnnotationMetadata metadata, DeferredImportSelector selector);
/**
* ص
*/
Iterable<Entry> selectImports()
}
}
ڴ DeferredImportSelector ĵʱDeferredImportSelector.Group#process ȵãȻٵ DeferredImportSelector.Group#selectImports صࣻ
DeferredImportSelector ָķ飬ڴʱ鴦ࣻ
DeferredImportSelector ڴʱȽఴһ map Уڴࣨspring Ϊ @Component``@ComponentScan``@Import``@Configuration``@Bean ǵࣩеĵ࣬Ҳ˵DeferredImportSelector ࣬עᵽ beanFactory кٽעᣨעǰжܷעᵽ beanFactoryܲעᣩ
AutoConfigurationImportSelector Ĵ룺
// ʵ DeferredImportSelector
public class AutoConfigurationImportSelector implements DeferredImportSelector,
BeanClassLoaderAware,ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
...
/**
* ʵ DeferredImportSelector.Group
*/
private static class AutoConfigurationGroup implements DeferredImportSelector.Group,
BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
/**
* 浼
*/
private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
/**
*
*/
@Override
public void process(AnnotationMetadata annotationMetadata,
DeferredImportSelector deferredImportSelector) {
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
() -> String.format("Only %s implementations are supported, got %s",
AutoConfigurationImportSelector.class.getSimpleName(),
deferredImportSelector.getClass().getName()));
// 1\. AutoConfigurationImportSelector#getAutoConfigurationEntry(...)
// Զװ
AutoConfigurationEntry autoConfigurationEntry =
((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 2\. ȡ autoConfigurationEntry
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
/**
* ص
*/
@Override
public Iterable<Entry> selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
// 3\. õ
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream)
.collect(Collectors.toSet());
// 4\. autoConfigurationEntries תΪ LinkedHashSet
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
// 5\. ȥҪ˵
processedConfigurations.removeAll(allExclusions);
// 6\.
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata())
.stream().map((importClassName) -> new Entry(
this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
...
}
}
ǽ DeferredImportSelector.Group#process DeferredImportSelector.Group#selectImports ܽ:
AutoConfigurationImportSelector#getAutoConfigurationEntry(...) ԶװࣻautoConfigurationEntries У@EnableAutoConfiguration exclude excludeName ָģautoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurationsprocessedConfigurations Ҫ˵ࣻǶЩؼз
ر˵
DeferredImportSelectorImportSelectorӽӿڣImportSelectorķselectImports(...)DeferredImportSelectorҲд˸÷ҲǼԶװ࣬յ࣬Ҫעǣspringboot Զ****ﴦģ㣬ڷڴϵ㣬Ȼͻᷢûе
£springboot Զ****
AutoConfigurationImportSelector#selectImportsдģAutoConfigurationImportSelector.AutoConfigurationGroup#selectImportsдġ
AutoConfigurationImportSelector#getAutoConfigurationEntryԶ ļشΪ
AutoConfigurationEntry autoConfigurationEntry =
((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
ôԶװģֱӽ AutoConfigurationImportSelector#getAutoConfigurationEntry
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata, AnnotationMetadata annotationMetadata) {
// һжǷԶװ
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// ȡע
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 1\. غѡԶ
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 2\. ȥأתsetתlist
configurations = removeDuplicates(configurations);
// 3\. ȥҪų࣬ʵǴ@EnableAutoConfigurationexcludeexcludeName
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
// 4\. ˲ҪԶװ
configurations = filter(configurations, autoConfigurationMetadata);
// 5\. AutoConfigurationImportEvent ¼
fireAutoConfigurationImportEvents(configurations, exclusions);
// 6\. շصֵ
return new AutoConfigurationEntry(configurations, exclusions);
}
dzҪ˻ȡԶװȫò£
غѡԶװ࣬springboot Զװλ classpath µ META-INF/spring.factories ļУkey Ϊ org.springframework.boot.autoconfigure.EnableAutoConfigurationǺϸ
ȥظԶװ࣬һصõԶװܻظȥظ࣬ȥʽҲdzspringboot ֻת Setת List
ȥų࣬ǰᵽ @EnableAutoConfiguration ͨ exclude excludeName ָҪų࣬һԵģ
˲ҪԶװ࣬ݱ˵ԣֲûɹˣ
ǰ 124
˺ 124
AutoConfigurationImportEvent ¼
3 õų 4 õԶװװ AutoConfigurationEntry ء
עһд룺
// 6\. շصֵ
return new AutoConfigurationEntry(configurations, exclusions);
configurations exclusions AutoConfigurationEntry Ĺ췽 AutoConfigurationEntry
protected static class AutoConfigurationEntry {
// Զװ
private final List<String> configurations;
// ҪųԶװ
private final Set<String> exclusions;
/**
* 췽߽иֵ
*/
AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
this.configurations = new ArrayList<>(configurations);
this.exclusions = new HashSet<>(exclusions);
}
...
}
Щɼշص AutoConfigurationEntry ݣ
configurationsԶװ࣬ѾȥҪųexclusionsͨ @EnableAutoConfiguration ָҪųԶװĻȡˣغѡԶװ̡
Զװļλ AutoConfigurationImportSelector#getCandidateConfigurations£
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
// õ spring ṩķSpringFactoriesLoader.loadFactoryNames(...)
// getSpringFactoriesLoaderFactoryClass() صEnableAutoConfiguration
List<String> configurations = SpringFactoriesLoader
.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
Assert.notEmpty(configurations, "...");
return configurations;
}
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
SpringFactoriesLoader#loadFactoryNames
public final class SpringFactoriesLoader {
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
// õ factoryTypeName org.springframework.boot.autoconfigure.EnableAutoConfiguration
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
}
/**
* мأص META-INF/spring.factories е
*/
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
// META-INF/spring.factories
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);
// META-INF/spring.factories תΪ Properties
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
// StringUtils.commaDelimitedListToStringArray(...) ŷָΪ
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);
}
}
...
}
Կص classpath µ META-INF/spring.factories ļע⣺ļܻжλڲͬ jar С
springboot Դ META-INF/spring.factories λ spring-boot-autoconfigure ģ£
һ spring.factories
ļ࣬ key-value ʽ棬ֵ֮ʹ , ֿᵽԶװ key org.springframework.boot.autoconfigure.EnableAutoConfigurationӦ value dz࣬Ͳչʾˡ
һ֮Զװͱעᵽ spring ˡעʱص spring еĻ BeanDefinitionҪΪ spring beanþ ConditionalOnBean``ConditionalOnClass עĿ飬ЩǺٷ
ٻص AutoConfigurationImportSelector.AutoConfigurationGroupڵ 1 ܽ£
AutoConfigurationImportSelector#getAutoConfigurationEntry(...) ԶװࣻautoConfigurationEntries У@EnableAutoConfiguration exclude excludeName ָģautoConfigurationEntries תΪ LinkedHashSetΪ processedConfigurationsprocessedConfigurations Ҫ˵ࣻϵ 2 3 ڣԶļع̣IJ衣
Ŵ룬ǻֽᷢIJ趼ȽϼҲһ˵°ɡ
2 õԶװֻ࣬ǵ List#add(...) õ autoConfigurationEntry 浽 autoConfigurationEntriesṹ AutoConfigurationGroup ijԱ AutoConfigurationImportSelector.AutoConfigurationGroup#selectImports лõ
3 õеĹ࣬ùDZ autoConfigurationEntriesȻͨ autoConfigurationEntry#getExclusions õ ǰҲᵽautoConfigurationEntry ֻԱconfigurations(ȥųԶװ) exclusions(ͨ @EnableAutoConfiguration ָų)
4 List תΪ LinkedHashSet
5 еԶװٽһȥųIJųĶеų࣬ӦǻͬһĿж @EnableAutoConfiguration һ @EnableAutoConfiguration עų A``B ࣬ڶ @EnableAutoConfiguration עų C``D ࣬ų A``B``C``D ĸࣻ
6 һҪ˳Զװעᵽ beanFactory е˳AutoConfigureOrder``@AutoConfigureAfter @AutoConfigureBefore ﴦģݣԲο springboot Զװ֮Զװ˳.
ЩԶװĻȡˡ
˽Զװļع̺ҲԶһԶװࡣ
@Configuration
public class MyAutoConfiguration {
@Bean
public Object object() {
System.out.println("create object");
return new Object();
}
}
ܼһ @Configuration ࣬ʹ @Bean עⴴһ beanڴ bean Ĺл ӡ "create object"
META-INF/spring.factories £# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.learn.autoconfigure.demo01.configure.MyAutoConfiguration
@SpringBootApplication
public class AutoconfigureDemo01Application {
public static void main(String[] args) {
SpringApplication.run(AutoconfigureDemo01Application.class, args);
}
}
н£
Կcreate object ɹӡˡ
bean ͨɨ贴ģԶװ䵼أͨԵķʽԶװõࣺ
ԿMyAutoConfiguration Զװбˡ
עMyAutoConfiguration @Configuration ע⣬ ô sping ɨ赽ģԶװõأ
springboot Դ@SpringBootApplication עһУᵽ SpringBootApplication עе @ComponentScan ָһAutoConfigurationExcludeFilterԶװ࣬ǿĿǰΪֹ beanFactory Щ beanName
Կû MyAutoConfiguration˴ʱûɨ beanFactory С
ȻҲ MyAutoConfiguration @Configuration עȥͲˡ
Ĵ @EnableAutoConfiguration עԶװļ̣ AutoConfigurationImportSelector#getAutoConfigurationEntry Уռص META-INF/spring.factories ļ key org.springframework.boot.autoconfigure.EnableAutoConfiguration ࡣ
õԶװspring ὫעᵽУʱǻһ BeanDefinitionҪΪ spring beanþ ConditionalOnBean``ConditionalOnClass עĿ飬ЩǺٷ
ԭӣhttps://my.oschina.net/funcy/blog/4870868 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע