SpringApplication.run 的加载过程通过选择器 AutoConfigurationImportSelector 进行自动配置加载。
AutoConfigurationImportSelector 类 process 处理过程获取了所有的配置 configurations,然后进行 filter 过滤。
/** class AutoConfigurationImportSelector **/// 使用DeferredImportSelector 处理SpringBootApplication注解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())); // 获取配置实体 getAutoConfigurationMetadata 获取自动配置元数据 AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector) .getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata); this.autoConfigurationEntries.add(autoConfigurationEntry); for (String importClassName : autoConfigurationEntry.getConfigurations()) { this.entries.putIfAbsent(importClassName, annotationMetadata); } }
复制代码
/** class AutoConfigurationImportSelector **/// 获取自动配置实体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); }
复制代码
/** class AutoConfigurationImportSelector **/// 获取自动配置元数据private AutoConfigurationMetadata getAutoConfigurationMetadata() { if (this.autoConfigurationMetadata == null) { this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader); } return this.autoConfigurationMetadata;}
/** class AutoConfigurationMetadataLoader **/final class AutoConfigurationMetadataLoader { protected static final String PATH = "META-INF/spring-autoconfigure-metadata.properties"; // 从配置文件 META-INF/spring-autoconfigure-metadata.properties 加载元数据 static AutoConfigurationMetadata loadMetadata(ClassLoader classLoader) { return loadMetadata(classLoader, PATH); }}
复制代码
AutoConfigurationMetadataLoader 类从 META-INF/spring-autoconfigure-metadata.properties 加载元数据。
RedisAutoConfiguration.ConditionalOnClass
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration.ConditionalOnClass=org.springframework.data.redis.core.RedisOperations
复制代码
继续看 filter 方法
从配置文件中加载了 AutoConfigurationImportFilter 的配置类,使用所有类进行匹配过滤。
每个配置类使用了 AutoConfigurationImportFilter 的 match 方法进行匹配,继而调用了实现类的 getOutcomes 进行检验。
private List<String> filter(List<String> configurations, AutoConfigurationMetadata autoConfigurationMetadata) {
String[] candidates = StringUtils.toStringArray(configurations); ... for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) { invokeAwareMethods(filter); boolean[] match = filter.match(candidates, autoConfigurationMetadata); ... } ...}
复制代码
getAutoConfigurationImportFilters() 方法使用 SpringFactoriesLoader 从配置文件 spring.factories 中加载 AutoConfigurationImportFilter 自动过滤类
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() { return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);}
复制代码
# spring.factories# Auto Configuration Import Filtersorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\org.springframework.boot.autoconfigure.condition.OnBeanCondition,\org.springframework.boot.autoconfigure.condition.OnClassCondition,\org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
复制代码
FilteringSpringBootCondition 类的继承关系
FilteringSpringBootCondition (org.springframework.boot.autoconfigure.condition)
|--OnBeanCondition (org.springframework.boot.autoconfigure.condition)
|--OnClassCondition (org.springframework.boot.autoconfigure.condition)
|--OnWebApplicationCondition (org.springframework.boot.autoconfigure.condition)
来看下 OnClassCondition 类条件的匹配
@Order(Ordered.HIGHEST_PRECEDENCE)class OnClassCondition extends FilteringSpringBootCondition {
@Override protected final ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { // Split the work and perform half in a background thread if more than one // processor is available. Using a single additional thread seems to offer the // best performance. More threads make things worse. // 多核处理器,使用一个额外的线程处理一半工作,以获得最优性能 if (Runtime.getRuntime().availableProcessors() > 1) { return resolveOutcomesThreaded(autoConfigurationClasses, autoConfigurationMetadata); } else { OutcomesResolver outcomesResolver = new StandardOutcomesResolver(autoConfigurationClasses, 0, autoConfigurationClasses.length, autoConfigurationMetadata, getBeanClassLoader()); return outcomesResolver.resolveOutcomes(); } }
复制代码
OnClassCondition 类获取匹配信息 通过 key ConditionalOnClass 来获取配置文件的类, matches 通过 classloader 进行加载类,不存在类则添加异常信息
/** class OnClassCondition **/private ConditionOutcome[] getOutcomes(String[] autoConfigurationClasses, int start, int end, AutoConfigurationMetadata autoConfigurationMetadata) { ConditionOutcome[] outcomes = new ConditionOutcome[end - start]; for (int i = start; i < end; i++) { String autoConfigurationClass = autoConfigurationClasses[i]; if (autoConfigurationClass != null) { String candidates = autoConfigurationMetadata.get(autoConfigurationClass, "ConditionalOnClass"); if (candidates != null) { outcomes[i - start] = getOutcome(candidates); } } } return outcomes; }
复制代码
ConditionalOnClass 注解匹配信息
/** class OnClassCondition **/private ConditionOutcome getOutcome(String className, ClassLoader classLoader) { if (ClassNameFilter.MISSING.matches(className, classLoader)) { return ConditionOutcome.noMatch(ConditionMessage.forCondition(ConditionalOnClass.class) .didNotFind("required class").items(Style.QUOTE, className)); } return null;}
复制代码
FilteringSpringBootCondition 使用 classLoader 进行类加载
/** class FilteringSpringBootCondition **/protected static Class<?> resolve(String className, ClassLoader classLoader) throws ClassNotFoundException { if (classLoader != null) { return classLoader.loadClass(className); } return Class.forName(className);}
复制代码
有趣的写法
enum 实现类继承
protected enum ClassNameFilter {
PRESENT {
@Override public boolean matches(String className, ClassLoader classLoader) { return isPresent(className, classLoader); }
},
MISSING {
@Override public boolean matches(String className, ClassLoader classLoader) { return !isPresent(className, classLoader); }
};
abstract boolean matches(String className, ClassLoader classLoader);
static boolean isPresent(String className, ClassLoader classLoader) { if (classLoader == null) { classLoader = ClassUtils.getDefaultClassLoader(); } try { resolve(className, classLoader); return true; } catch (Throwable ex) { return false; } }
}
复制代码
总结
SpringBoot 自动配置过程AutoConfigurationImportSelector选择器 process 处理过程,通过 filter 进行配置过滤处理,filter 是从配置文件 spring.factories 中获取FilteringSpringBootCondition配置类(OnBeanCondition、OnClassCondition、OnWebApplicationCondition),OnClassCondition实现对ConditionalOnClass的处理,springBoot 从配置文件 spring-autoconfigure-metadata.properties 获取的元数据 autoConfigurationMetadata 中获取 key 为 ConditionalOnClass 的配置类,通过ClassLoader进行类加载,类不存在则过滤掉不再进行配置类加载。
那么 @ConditionOnClass 编译是怎么处理的呢?
使用 optional 选项
<dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>2.2.5.RELEASE</version> <scope>compile</scope> <optional>true</optional></dependency>
复制代码
评论