package org.springframework.boot.autoconfigure;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.linkedHashMap;
import java.util.linkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DeferredimportSelector;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.SpringFactoriesLoader;
import org.springframework.core.type.Annotationmetadata;
import org.springframework.core.type.classreading.CachingmetadataReaderFactory;
import org.springframework.core.type.classreading.metadataReaderFactory;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
public class AutoConfigurationimportSelector implements DeferredimportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
private static final AutoConfigurationEntry EMPTY_ENTRY = new AutoConfigurationEntry();
private static final String[] NO_importS = {};
private static final Log logger = LogFactory.getLog(AutoConfigurationimportSelector.class);
private static final String PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE = "spring.autoconfigure.exclude";
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
//是否启用自动配置
if (!isEnabled(annotationmetadata)) {
return NO_importS;
}
//获取meta-INF/spring-autoconfigure-metadata.properties文件的配置,返回AutoConfigurationmetadata类
AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader
.loadmetadata(this.beanClassLoader);
//获取自动配置类,返回AutoConfigurationEntry
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationmetadata,
annotationmetadata);
//返回要自动配置的类名
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationmetadata autoConfigurationmetadata,
Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationmetadata);
//meta-INF/spring.factories下获取路径是org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置
List configurations = getCandidateConfigurations(annotationmetadata, attributes);
//去重,并可以由子类拓展
configurations = removeDuplicates(configurations);
//获取排除的自动配置
Set exclusions = getExclusions(annotationmetadata, attributes);
//校验配置信息是否可加载,并且不能排除自动配置信息
checkExcludedClasses(configurations, exclusions);
//从自动配置移除忽略的
configurations.removeAll(exclusions);
//通过meta-INF/spring.factories下AutoConfigurationimportFilter来过滤不需要的bean.
//也就是通过OnBeanCondition,OnClassCondition,OnWebApplicationCondition来过滤不需要的bean.
configurations = filter(configurations, autoConfigurationmetadata);
//执行自动装配加载的监听器
fireAutoConfigurationimportEvents(configurations, exclusions);
//封装到AutoConfigurationEntry并返回
return new AutoConfigurationEntry(configurations, exclusions);
}
@Override
public Class extends Group> getimportGroup() {
return AutoConfigurationGroup.class;
}
protected boolean isEnabled(Annotationmetadata metadata) {
//如果是当前类是AutoConfigurationimportSelector
if (getClass() == AutoConfigurationimportSelector.class) {
//从当前环境中获取spring.boot.enableautoconfiguration是否启用自动配置,默认为true
return getEnvironment().getProperty(EnableAutoConfiguration.ENABLED_OVERRIDE_PROPERTY, Boolean.class, true);
}
return true;
}
protected AnnotationAttributes getAttributes(Annotationmetadata metadata) {
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;
}
protected Class> getAnnotationClass() {
return EnableAutoConfiguration.class;
}
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;
}
protected Class> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
private void checkExcludedClasses(List configurations, Set exclusions) {
List invalidExcludes = new ArrayList<>(exclusions.size());
for (String exclusion : exclusions) {
//校验是否可以加载,并且要加载的属性中不包含排除的
if (ClassUtils.isPresent(exclusion, getClass().getClassLoader()) && !configurations.contains(exclusion)) {
invalidExcludes.add(exclusion);
}
}
//如果不能加载或者自动配置里不包含排除的配置项,抛异常提示报错
if (!invalidExcludes.isEmpty()) {
handleInvalidExcludes(invalidExcludes);
}
}
protected void handleInvalidExcludes(List invalidExcludes) {
StringBuilder message = new StringBuilder();
for (String exclude : invalidExcludes) {
message.append("t- ").append(exclude).append(String.format("%n"));
}
throw new IllegalStateException(String.format(
"The following classes could not be excluded because they are not auto-configuration classes:%n%s",
message));
}
protected Set getExclusions(Annotationmetadata metadata, AnnotationAttributes attributes) {
Set excluded = new linkedHashSet<>();
excluded.addAll(asList(attributes, "exclude"));
excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
excluded.addAll(getExcludeAutoConfigurationsProperty());
return excluded;
}
private List getExcludeAutoConfigurationsProperty() {
if (getEnvironment() instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(getEnvironment());
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = getEnvironment().getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
private List filter(List 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 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);
}
protected List getAutoConfigurationimportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationimportFilter.class, this.beanClassLoader);
}
protected final List removeDuplicates(List list) {
return new ArrayList<>(new linkedHashSet<>(list));
}
protected final List asList(AnnotationAttributes attributes, String name) {
String[] value = attributes.getStringArray(name);
return Arrays.asList((value != null) ? value : new String[0]);
}
private void fireAutoConfigurationimportEvents(List configurations, Set exclusions) {
//获取到自动配置的监听器
List listeners = getAutoConfigurationimportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationimportEvent event = new AutoConfigurationimportEvent(this, configurations, exclusions);
for (AutoConfigurationimportListener listener : listeners) {
//设置Aware
invokeAwareMethods(listener);
//执行监听器
listener.onAutoConfigurationimportEvent(event);
}
}
}
protected List getAutoConfigurationimportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationimportListener.class, this.beanClassLoader);
}
private void invokeAwareMethods(Object instance) {
if (instance instanceof Aware) {
if (instance instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);
}
if (instance instanceof BeanFactoryAware) {
((BeanFactoryAware) instance).setBeanFactory(this.beanFactory);
}
if (instance instanceof EnvironmentAware) {
((EnvironmentAware) instance).setEnvironment(this.environment);
}
if (instance instanceof ResourceLoaderAware) {
((ResourceLoaderAware) instance).setResourceLoader(this.resourceLoader);
}
}
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
Assert.isInstanceOf(ConfigurableListableBeanFactory.class, beanFactory);
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
protected final ConfigurableListableBeanFactory getBeanFactory() {
return this.beanFactory;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
protected final Environment getEnvironment() {
return this.environment;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
protected final ResourceLoader getResourceLoader() {
return this.resourceLoader;
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE - 1;
}
private static class AutoConfigurationGroup
implements DeferredimportSelector.Group, BeanClassLoaderAware, BeanFactoryAware, ResourceLoaderAware {
private final Map entries = new linkedHashMap<>();
private final List autoConfigurationEntries = new ArrayList<>();
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private ResourceLoader resourceLoader;
private AutoConfigurationmetadata autoConfigurationmetadata;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@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()));
//获取自动装配的配置
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationimportSelector) deferredimportSelector)
.getAutoConfigurationEntry(getAutoConfigurationmetadata(), annotationmetadata);
this.autoConfigurationEntries.add(autoConfigurationEntry);
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
this.entries.putIfAbsent(importClassName, annotationmetadata);
}
}
@Override
public Iterable selectimports() {
if (this.autoConfigurationEntries.isEmpty()) {
return Collections.emptyList();
}
//获取要排除的
Set allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
//获取到自动当前自动装配的属性
Set 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());
}
private AutoConfigurationmetadata getAutoConfigurationmetadata() {
if (this.autoConfigurationmetadata == null) {
this.autoConfigurationmetadata = AutoConfigurationmetadataLoader.loadmetadata(this.beanClassLoader);
}
return this.autoConfigurationmetadata;
}
private List sortAutoConfigurations(Set configurations,
AutoConfigurationmetadata autoConfigurationmetadata) {
return new AutoConfigurationSorter(getmetadataReaderFactory(), autoConfigurationmetadata)
.getInPriorityOrder(configurations);
}
private metadataReaderFactory getmetadataReaderFactory() {
try {
return this.beanFactory.getBean(SharedmetadataReaderFactoryContextInitializer.BEAN_NAME,
metadataReaderFactory.class);
} catch (NoSuchBeanDefinitionException ex) {
return new CachingmetadataReaderFactory(this.resourceLoader);
}
}
}
protected static class AutoConfigurationEntry {
private final List configurations;
private final Set exclusions;
private AutoConfigurationEntry() {
this.configurations = Collections.emptyList();
this.exclusions = Collections.emptySet();
}
AutoConfigurationEntry(Collection configurations, Collection exclusions) {
this.configurations = new ArrayList<>(configurations);
this.exclusions = new HashSet<>(exclusions);
}
public List getConfigurations() {
return this.configurations;
}
public Set getExclusions() {
return this.exclusions;
}
}
}