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 Filters
org.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>