概要
何为自动装配?自动装配可简单理解为Spring自动读取配置类信息,并解析配置类中的Bean信息,然后将相关Bean初始化到IOC容器中。前面两个章节已经了解了SPI技术和Spring中Import注解的实现原理,本章节来具体讲解Spring boot如何使用通过EnableAutoConfiguration注解将Bean自动注入到Spring容器中。
源码剖析
Spring Boot将相关配置都集成到了SpringBootApplication注解,在启动类加上该注解则标识为Spring Boot应用,进入SpringBootApplication类可以看到该类集成了@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解,SpringBootConfiguration继承了@Configuration,标识该类为Spring的配置类,在Spring启动IOC容器的时候可以识别并解析,ComponentScan表示IOC容器启动时,需要去扫描注册的Spring组件,EnableAutoConfiguration即标识开启Spring Boot 自动配置,进入之后发现其主要包含了两个注解,一个为AutoConfigurationPackage,另一个为Import,AutoConfigurationPackage默认没有扫描的包路径暂忽略,Import注解导入了AutoConfigurationImportSelector,该类为Spring Boot自动装配核心类,通过该类自动装载了Spring Boot需要的对象到IOC,下面对该类进行重点讲解。
首先上源码
AutoConfigurationImportSelector
.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;
// 类加载器(AppClassLoader)
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
private ConfigurationClassFilter configurationClassFilter;
@Override
// 获取需要自动装载的Bean的classname集合
// ConfigurationClassPostProcessor解析配置类的时候会调用该方法
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 是否需要导入类,默认需要,不会进入此判断
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
// 获取自动装配对象(里面包含需要解析的配置类)
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);
// 返回自动装配Bean的classname集合
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
@Override
public Predicate<String> getExclusionFilter() {
return this::shouldExclude;
}
private boolean shouldExclude(String configurationClassName) {
return getConfigurationClassFilter().filter(Collections.singletonList(configurationClassName)).isEmpty();
}
/**
* Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
* of the importing {@link Configuration @Configuration} class.
* @param annotationMetadata the annotation metadata of the configuration class
* @return the auto-configurations that should be imported
*/
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
// 获取配置类所有注解属性,此处传入的类为EnableAutoConfiguration,获取到exclude和excludeName属性
AnnotationAttributes attributes = getAttributes(annotationMetadata);
// 获取配置类标注的所有候选配置类信息
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去除重复项
configurations = removeDuplicates(configurations);
// 获取需要排除的配置类(不需要注入容器的Bean)
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查排除的配置类的合法性,如果不合法则抛出异常
checkExcludedClasses(configurations, exclusions);
// 从需要解析的配置类集合中剔除需要排除的配置类
configurations.removeAll(exclusions);
// 获取配置类过滤器对配置类进行过滤
configurations = getConfigurationClassFilter().filter(configurations);
// 开启记录自动化配置过程中条件匹配的详细信息及日志信息
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
@Override
public Class<? extends Group> getImportGroup() {
return AutoConfigurationGroup.class;
}
protected boolean isEnabled(AnnotationMetadata metadata) {
if (getClass() == AutoConfigurationImportSelector.class) {
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;
}
/**
* Return the source annotation class used by the selector.
* @return the annotation class
*/
protected Class<?> getAnnotationClass() {
return EnableAutoConfiguration.class;
}
/**
* Return the auto-configuration class names that should be considered. By default
* this method will load candidates using {@link SpringFactoriesLoader} with
* {@link #getSpringFactoriesLoaderFactoryClass()}.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return a list of candidate configurations
*/
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
/**
* 通过SpringFactoriesLoader去所有jar包中META-INF/spring.factories路径下获取
* 标注key为org.springframework.boot.autoconfigure.EnableAutoConfiguration(getSpringFactoriesLoaderFactoryClass返回值)的所有配置类。
* org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
* org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
* org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
* org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
* SpringFactoriesLoader.loadFactoryNames运用SPI的机制读取文件内容(不清楚SPI可以参考第一章节)
**/
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;
}
/**
* Return the class used by {@link SpringFactoriesLoader} to load configuration
* candidates.
* @return the factory class
*/
protected Class<?> getSpringFactoriesLoaderFactoryClass() {
return EnableAutoConfiguration.class;
}
private void checkExcludedClasses(List<String> configurations, Set<String> exclusions) {
// 如果排除的配置类能能正常加载,并且在自动装配的配置类集合中不存在,则添加到非验证的排除类集合中
List<String> 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);
}
}
/**
* Handle any invalid excludes that have been specified.
* @param invalidExcludes the list of invalid excludes (will always have at least one
* element)
*/
protected void handleInvalidExcludes(List<String> 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));
}
/**
* Return any exclusions that limit the candidate configurations.
* @param metadata the source metadata
* @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
* attributes}
* @return exclusions or an empty set
*/
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;
}
/**
* Returns the auto-configurations excluded by the
* {@code spring.autoconfigure.exclude} property.
* @return excluded auto-configurations
* @since 2.3.2
*/
protected List<String> getExcludeAutoConfigurationsProperty() {
Environment environment = getEnvironment();
if (environment == null) {
return Collections.emptyList();
}
if (environment instanceof ConfigurableEnvironment) {
Binder binder = Binder.get(environment);
return binder.bind(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class).map(Arrays::asList)
.orElse(Collections.emptyList());
}
String[] excludes = environment.getProperty(PROPERTY_NAME_AUTOCONFIGURE_EXCLUDE, String[].class);
return (excludes != null) ? Arrays.asList(excludes) : Collections.emptyList();
}
protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class, this.beanClassLoader);
}
private ConfigurationClassFilter getConfigurationClassFilter() {
if (this.configurationClassFilter == null) {
/**
* 获取配置类过滤器
* 通过SpringFactoriesLoader去所有jar包中(此处为spring-boot-autoconfigure jar包)META-INF/spring.factories中
* 标注key为oorg.springframework.boot.autoconfigure.AutoConfigurationImportFilter的所有过滤器
* org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
* org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
* org.springframework.boot.autoconfigure.condition.OnClassCondition,\
* org.springframework.boot.autoconfigure.condition.OnWebApplicationCondition
* 这些类作用于Conditional开头的注解,例如ConditionalOnBean、ConditionalOnMissingBean、ConditionalOnMissingClass等
*/
List<AutoConfigurationImportFilter> filters = getAutoConfigurationImportFilters();
for (AutoConfigurationImportFilter filter : filters) {
// 调用Aware接口方法,将相关属性设置到Aware实现类的属性中,
//此处是将容器的工厂设置到过滤器的beanFactory属性中
invokeAwareMethods(filter);
}
this.configurationClassFilter = new ConfigurationClassFilter(this.beanClassLoader, filters);
}
return this.configurationClassFilter;
}
// 通过set去重
protected final <T> List<T> removeDuplicates(List<T> list) {
return new ArrayList<>(new LinkedHashSet<>(list));
}
protected final List<String> asList(AnnotationAttributes attributes, String name) {
String[] value = attributes.getStringArray(name);
return Arrays.asList(value);
}
private void fireAutoConfigurationImportEvents(List<String> configurations, Set<String> exclusions) {
/**
* 通过SpringFactoriesLoader去所有jar包中(此处为spring-boot-autoconfigure jar包)META-INF/spring.factories中
* 标注key为oorg.springframework.boot.autoconfigure.AutoConfigurationImportListener的所有监听器
* org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
* org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
*/
List<AutoConfigurationImportListener> listeners = getAutoConfigurationImportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationImportEvent event = new AutoConfigurationImportEvent(this, configurations, exclusions);
for (AutoConfigurationImportListener listener : listeners) {
// 调用Aware接口方法,将相关属性设置到Aware实现类的属性中,
//此处是将容器的工厂设置到过滤器的beanFactory属性中
invokeAwareMethods(listener);
listener.onAutoConfigurationImportEvent(event);
}
}
}
protected List<AutoConfigurationImportListener> getAutoConfigurationImportListeners() {
return SpringFactoriesLoader.loadFactories(AutoConfigurationImportListener.class, this.beanClassLoader);
}
private void invokeAwareMethods(Object instance) {
if (instance instanceof Aware) {
// 设置Bean的类装载器
if (instance instanceof BeanClassLoaderAware) {
((BeanClassLoaderAware) instance).setBeanClassLoader(this.beanClassLoader);
}
// 设置Bean工厂
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);
}
}
}
......
private static class ConfigurationClassFilter {
private final AutoConfigurationMetadata autoConfigurationMetadata;
private final List<AutoConfigurationImportFilter> filters;
ConfigurationClassFilter(ClassLoader classLoader, List<AutoConfigurationImportFilter> filters) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(classLoader);
this.filters = filters;
}
// 将不符合的配置类剔除,例如配置了ConditionalOnMissingClass,则表示ConditionalOnMissingClass注解中配置的类不存在才会加载当前类
List<String> filter(List<String> configurations) {
long startTime = System.nanoTime();
String[] candidates = StringUtils.toStringArray(configurations);
boolean skipped = false;
for (AutoConfigurationImportFilter filter : this.filters) {
/**
* 对需要加载的配置类进行过滤处理,
* 处理配置了Conditional开头的注解的配置类,
* 具体过滤规则可阅读FilteringSpringBootCondition的match方法
*/
boolean[] match = filter.match(candidates, this.autoConfigurationMetadata);
for (int i = 0; i < match.length; i++) {
// 如果过滤规则匹配成功,则将配置类删除(数组元素赋空)
if (!match[i]) {
candidates[i] = null;
skipped = true;
}
}
}
// 匹配不到返回原配置类集合
if (!skipped) {
return configurations;
}
// 将空的配置类删除,并返回删除之后的配置类集合
List<String> result = new ArrayList<>(candidates.length);
for (String candidate : candidates) {
if (candidate != null) {
result.add(candidate);
}
}
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 result;
}
}
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<>();
......
@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(annotationMetadata);
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();
}
// 获取需要排除的类
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());
}
private AutoConfigurationMetadata getAutoConfigurationMetadata() {
if (this.autoConfigurationMetadata == null) {
this.autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);
}
return this.autoConfigurationMetadata;
}
private List<String> sortAutoConfigurations(Set<String> 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<String> configurations;
private final Set<String> exclusions;
private AutoConfigurationEntry() {
this.configurations = Collections.emptyList();
this.exclusions = Collections.emptySet();
}
/**
* Create an entry with the configurations that were contributed and their
* exclusions.
* @param configurations the configurations that should be imported
* @param exclusions the exclusions that were applied to the original list
*/
AutoConfigurationEntry(Collection<String> configurations, Collection<String> exclusions) {
this.configurations = new ArrayList<>(configurations);
this.exclusions = new HashSet<>(exclusions);
}
public List<String> getConfigurations() {
return this.configurations;
}
public Set<String> getExclusions() {
return this.exclusions;
}
}
}
由于AutoConfigurationImportSelector实现了DeferredImportSelector(延迟导入)接口,其自动装配会经过ConfigurationClassParser进行后置处理(this.deferredImportSelectorHandler.process(),通过ConfigurationClassParserKaTeX parse error: Expected 'EOF', got '#' at position 30: …SelectorHandler#̲process方法处理)。 D…Group(即不能的选择器分配到不同的组),然后调用分组内部方法process(DeferredImportSelectorKaTeX parse error: Expected 'EOF', got '#' at position 6: Group#̲process)解析META-…Group#selectImports)返回需要进行自动装配的配置类实体集合,之后交给ConfigurationClassParser#processImports进行解析。
private class DeferredImportSelectorHandler {
@Nullable
private List<DeferredImportSelectorHolder> deferredImportSelectors = new ArrayList<>();
......
// 延迟导入选择器后置解析入口
public void process() {
List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
this.deferredImportSelectors = null;
try {
if (deferredImports != null) {
DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
// 排序
deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
// 循环调用DeferredImportSelectorGroupingHandler#register方法,将选择器分组信息注入
deferredImports.forEach(handler::register);
// 调用DeferredImportSelectorGroupingHandler#processGroupImports方法处理组内需要导入的配置类
handler.processGroupImports();
}
}
finally {
this.deferredImportSelectors = new ArrayList<>();
}
}
}
private class DeferredImportSelectorGroupingHandler {
private final Map<Object, DeferredImportSelectorGrouping> groupings = new LinkedHashMap<>();
private final Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap<>();
public void register(DeferredImportSelectorHolder deferredImport) {
// 调用DeferredImportSelector#getImportGroup方法获取分组信息
// AutoConfigurationImportSelector#getImportGroup
Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
// 如果groupings集合中存在当前分组则直接返回分组信息,否则存入结合再返回
DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
(group != null ? group : deferredImport),
key -> new DeferredImportSelectorGrouping(createGroup(group)));
// 延迟导入选择器分组对象存入当前延迟导入选择器处理Bean,等待回调选择器的process方法的时候传入
// AutoConfigurationImportSelector$AutoConfigurationGroup#process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector)
// 此处的deferredImportSelector为AutoConfigurationImportSelector
grouping.add(deferredImport);
this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getConfigurationClass());
}
public void processGroupImports() {
for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
Predicate<String> exclusionFilter = grouping.getCandidateFilter();
grouping.getImports().forEach(entry -> {
ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
try {
// 递归解析需要注入的配置类
processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
exclusionFilter, false);
}
......
});
}
}
......
}
private static class DeferredImportSelectorGrouping {
......
public Iterable<Group.Entry> getImports() {
for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
// 调用后置导入选择器分组process方法(AutoConfigurationImportSelector$AutoConfigurationGroup#process,获取需要装载的配置类集合)
this.group.process(deferredImport.getConfigurationClass().getMetadata(),
deferredImport.getImportSelector());
}
// 调用后置导入选择器分组selectImports方法返回需要装载的配置类实体集合
return this.group.selectImports();
}
......
}
ImportSelector是直接调用ImportSelector#selectImports方法,获取需要自动装配的配置类classname集合,之后交给ConfigurationClassParser#processImports进行解析。
总结:
Spring Boot自动装配的流程是先通过SpringApplication将@SpringApplication注解类注入到Spring IOC容器,然后通过ConfigurationClassParser对标注@Configuration的类进行解析,当解析到@EnableAutoConfiguration注解的时候,发现其内部通过Import注解导入了AutoConfigurationImportSelector类,ConfigurationClassParser通过processImports方法去解析AutoConfigurationImportSelector。AutoConfigurationImportSelector通过selectImports方法运用SPI机制获取Spring Boot所有jar包内META-INF/spring.factories文件内路径标注key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的配置类,然后通过一些列的excludeFilter排除相关配置类,获取到相关配置类之后,交由ConfigurationClassParser解析出来,并存入Spring IOC容器对应BeanFactory的beanDefinitionMap中,最终通过DefaultListableBeanFactory#preInstantiateSingletons进行实例化,该过程就将Spring Boot的一些Bean自动注入到了Spring IOC容器中。