目錄
1、getAutoConfigurationMetadata
1)、獲取EnableAutoConfiguration註解的exclude和excludeName屬性值
2)、獲取spring.factories中EnableAutoConfiguration的配置值
5)、checkExcludedClasses(檢查需要排除的項目)
6)、發送AutoConfigurationImportEvent事件
7)、創建AutoConfigurationEntry對象返回
繼續上一篇,知道了執行時機和調用順序,繼續分析兩個方法的邏輯,是怎樣實現自動裝配的。開始之前先看看其類結構(屬性)AutoConfigurationImportSelector.AutoConfigurationGroup
private static class AutoConfigurationGroup
implements DeferredImportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
// 存儲註解對象關係
private final Map<String, AnnotationMetadata> entries = new LinkedHashMap<>();
// 存儲自動裝配的數據
private final List<AutoConfigurationEntry> autoConfigurationEntries = new ArrayList<>();
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
// 存儲自動裝配的,後置處理器,默認order值等信息
private AutoConfigurationMetadata autoConfigurationMetadata;
}
一、process
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 斷言判斷,肯定爲true
Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector, // 省略部分代碼);
// 向上轉型,調用父類的方法
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 添加到autoConfigurationEntries屬性中
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 將bean信息添加到entries(Map<String, AnnotationMetadata>)中
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
獲取AutoConfigurationEntry類型的返回結果,組裝數據到AutoConfigurationGroup的autoConfigurationEntries和entries中。主要的方法在getAutoConfigurationMetadata中,但是在調用前會加載autoConfigurationMetadata數據。
1、getAutoConfigurationMetadata
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) {
// String PATH = "META-INF/spring-autoconfigure-metadata.properties";
return loadMetadata(classLoader, PATH);
}
static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader, String path) {
try {
Enumeration<URL> urls = (classLoader != null) ? classLoader.getResources(path)
: ClassLoader.getSystemResources(path);
Properties properties = new Properties();
while (urls.hasMoreElements()) {
properties.putAll(PropertiesLoaderUtils.loadProperties(new UrlResource(urls.nextElement())));
}
return loadMetadata(properties);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load @ConditionalOnClass location [" + path + "]", ex);
}
}
查詢的文件路徑爲 "META-INF/spring-autoconfigure-metadata.properties",總共有488項key、value對應值。並將其值加載成爲Properties類型數據。先看看配置文件大概的內容:
org...RestTemplateAutoConfiguration.AutoConfigureAfter=org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
org...CassandraReactiveDataAutoConfiguration.ConditionalOnClass=com.datastax.driver.core.Cluster,reactor.core.publisher.Flux,org.springframework.data.cassandra.core.ReactiveCassandraTemplate
org...JerseyAutoConfiguration.AutoConfigureOrder=-2147483648
大致有三種類型(爲後續spring.factories中的自動裝配類,進行條件判斷,過濾使用):
1)、...XXAutoConfiguration.AutoConfigureAfter 誰的自動裝配的後置處理器類型
2)、...XXAutoConfiguration.ConditionalOnClass 誰的自動裝配的裝配條件
3)、...XXAutoConfiguration.AutoConfigureorder 誰的自動裝配的排序字段值
再繼續看看最後加裝的類型(最好加裝爲PropertiesAutoConfigurationMetadata類型,存放到Spring的Properties類型中,就是一個Hashtable):
static AutoConfigurationMetadata loadMetadata(Properties properties) {
return new PropertiesAutoConfigurationMetadata(properties);
}
2、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);
}
1)、獲取EnableAutoConfiguration註解的exclude和excludeName屬性值
只是默認情況下使用@EnableAutoConfiguration直接都是直接使用的@SpringBootApplication,所以獲取到的屬性值都爲默認值(爲空)。
protected AnnotationAttributes getAttributes(AnnotationMetadata metadata) {
// org.springframework.boot.autoconfigure.EnableAutoConfiguration
String name = getAnnotationClass().getName();
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
+ " annotated with " + ClassUtils.getShortName(name) + "?");
return attributes;
}
2)、獲取spring.factories中EnableAutoConfiguration的配置值
在調用前需要查看加載的類型:
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
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;
}
在啓動Spring Boot項目時,分析過會加載META-INF/spring.factories中的所有配置信息。正確流程情況下會在SpringApplic
ation.run方法中,加載SpringApplicationRunListener類型時就會去加載該properties中的信息,其中有一項大致爲:
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
。。。。。。
3)、removeDuplicates(去重)
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
雖然比較簡單,但是是我們在寫項目的時候可以進行借鑑的方式。
4)、獲取需要排除(不自動裝配)的類
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> excluded = new LinkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
不僅處理了之前getAttributes加載的@EnableConfiguration上的配置值,還添加了getExcludeAutoConfigurationsProperty中,在Environment中加載的值。當然,默認情況下所有值都爲空。
5)、checkExcludedClasses(檢查需要排除的項目)
循環遍歷排除項,如果在自動裝配項中不存在需要排除的項,則組裝檢查異常IllegalStateException並拋出。所以不能隨便寫排除項。
6)、剔除排除項
// 根據上面的排除項集合,剔除排除項
configurations.removeAll(exclusions);
// 根據加載的spring-autoconfigure-metadata.properties條件,進行排除
configurations = filter(configurations, autoConfigurationMetadata);
private List<String> filter(List<String> configurations, AutoConfigurationMetadata
autoConfigurationMetadata) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean[] skip = new boolean[candidates.length];
boolean skipped = false;
for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {
invokeAwareMethods(filter);
boolean[] match = filter.match(candidates, autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
if (!match[i]) {
skip[i] = true;
candidates[i] = null;
skipped = true;
}
}
}
if (!skipped) {
return configurations;
}
List<String> result = new ArrayList<>(candidates.length);
for (int i = 0; i < candidates.length; i++) {
if (!skip[i]) {
result.add(candidates[i]);
}
}
if (logger.isTraceEnabled()) {
int numberFiltered = configurations.size() - result.size();
logger.trace("Filtered " + numberFiltered + " auto configuration class in "
+ TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) + " ms");
}
return new ArrayList<>(result);
}
1)、先獲取spring.factories中的AutoConfigurationImportFilter類型。
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
org.springframework.boot.autoconfigure.condition.OnClassCondition,\
org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
2)、遍歷上面的三種類型,並且回調三種類型的BeanClassLoaderAware、BeanFactoryAware、EnvironmentAware、ResourceLoaderAware接口進行賦值。
3)、再結合spring-autoconfigure-metadata.properties中加載的具體類型調用match方法進行判定。
4)、組裝過濾後的最終需要自動裝配的類型,返回。
6)、發送AutoConfigurationImportEvent事件
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
獲取事件監聽列表,遍歷回調Aware接口,發送AutoConfigurationImportEvent 事件。
監聽列表也是自動裝配的spring.factories中的AutoConfigurationImportListener類型。
7)、創建AutoConfigurationEntry對象返回
根據需要自動裝配的類型列表和需要排除的對象列表,創建AutoConfigurationEntry類型對象返回,爲後續的selectImports回調做準備。
二、selectImports
@Override
public Iterable<Entry> selectImports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream)
.collect(Collectors.toSet());
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
processedConfigurations.removeAll(allExclusions);
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
1)、從List<AutoConfigurationEntry> autoConfigurationEntries中,獲取需要排除的HashSet
2)、從List<AutoConfigurationEntry> autoConfigurationEntries中,獲取自動裝配的List並轉化爲LinkedHashSet
3)、從自動裝配列表中剔除需要排除的項
4)、將自動裝配項進行排序,並且組裝成DeferredImportSelector.Group.Entry類型,返回。