SpringBoot的自动装配是拆箱即用的基础,也是微服务化的前提。这次主要的议题是,来看看它是怎么样实现的,我们透过源代码来把握自动装配的来龙去脉。
一、自动装配过程分析1.1、关于@SpringBootApplication
我们在编写SpringBoot项目时,@SpringBootApplication是最常见的注解了,我们可以看一下源代码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.annotation.AliasFor;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "exclude")
Class>[] exclude() default {};
@AliasFor(annotation = EnableAutoConfiguration.class, attribute = "excludeName")
String[] excludeName() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanbasePackages() default {};
@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
Class>[] scanbasePackageClasses() default {};
}
这里面包含了@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan,此处@ComponentScan由于没有指定扫描包,因此它默认扫描的是与该类同级的类或者同级包下的所有类,另外@SpringBootConfiguration,通过源码得知它是一个@Configuration:
package org.springframework.boot;
import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Configuration;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Configuration
public @interface SpringBootConfiguration {
}
由此我们可以推断出@SpringBootApplication等同于@Configuration @ComponentScan @EnableAutoConfiguration
1.2、@EnableAutoConfiguration
一旦加上此注解,那么将会开启自动装配功能,简单点讲,Spring会试图在你的classpath下找到所有配置的Bean然后进行装配。当然装配Bean时,会根据若干个(Conditional)定制规则来进行初始化。我们看一下它的源码:
package org.springframework.boot.autoconfigure;
import java.lang.annotation.documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.import;
import org.springframework.core.io.support.SpringFactoriesLoader;
@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@documented
@Inherited
@AutoConfigurationPackage
@import(EnableAutoConfigurationimportSelector.class)
public @interface EnableAutoConfiguration {
String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
Class>[] exclude() default {};
String[] excludeName() default {};
}
虽然根据文档注释的说明它指点我们去看EnableAutoConfigurationimportSelector。但是该类在SpringBoot1.5.X版本已经过时了,因此我们看一下它的父类AutoConfigurationimportSelector:
package org.springframework.boot.autoconfigure;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.linkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
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.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
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 String[] NO_importS = {};
private static final Log logger = LogFactory
.getLog(AutoConfigurationimportSelector.class);
private ConfigurableListableBeanFactory beanFactory;
private Environment environment;
private ClassLoader beanClassLoader;
private ResourceLoader resourceLoader;
@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return NO_importS;
}
try {
AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader
.loadmetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationmetadata);
List configurations = getCandidateConfigurations(annotationmetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationmetadata);
Set exclusions = getExclusions(annotationmetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationmetadata);
fireAutoConfigurationimportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
protected boolean isEnabled(Annotationmetadata metadata) {
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) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(
this.environment, "spring.autoconfigure.");
Map properties = resolver.getSubProperties("exclude");
if (properties.isEmpty()) {
return Collections.emptyList();
}
List excludes = new ArrayList();
for (Map.Entry entry : properties.entrySet()) {
String name = entry.getKey();
Object value = entry.getValue();
if (name.isEmpty() || name.startsWith("[") && value != null) {
excludes.addAll(new HashSet(Arrays.asList(StringUtils
.tokenizeToStringArray(String.valueOf(value), ","))));
}
}
return excludes;
}
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(getEnvironment(),
"spring.autoconfigure.");
String[] exclude = resolver.getProperty("exclude", String[].class);
return (Arrays.asList(exclude == null ? new String[0] : exclude));
}
private List sort(List configurations,
AutoConfigurationmetadata autoConfigurationmetadata) throws IOException {
configurations = new AutoConfigurationSorter(getmetadataReaderFactory(),
autoConfigurationmetadata).getInPriorityOrder(configurations);
return configurations;
}
private List filter(List configurations,
AutoConfigurationmetadata autoConfigurationmetadata) {
long startTime = System.nanoTime();
String[] candidates = configurations.toArray(new String[configurations.size()]);
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;
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);
}
private metadataReaderFactory getmetadataReaderFactory() {
try {
return getBeanFactory().getBean(
SharedmetadataReaderFactoryContextInitializer.BEAN_NAME,
metadataReaderFactory.class);
}
catch (NoSuchBeanDefinitionException ex) {
return new CachingmetadataReaderFactory(this.resourceLoader);
}
}
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 ? new String[0] : value);
}
private void fireAutoConfigurationimportEvents(List configurations,
Set exclusions) {
List listeners = getAutoConfigurationimportListeners();
if (!listeners.isEmpty()) {
AutoConfigurationimportEvent event = new AutoConfigurationimportEvent(this,
configurations, exclusions);
for (AutoConfigurationimportListener listener : listeners) {
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;
}
}
首先该类实现了DeferredimportSelector接口,这个接口继承了importSelector:
package org.springframework.context.annotation;
import org.springframework.core.type.Annotationmetadata;
public interface importSelector {
String[] selectimports(Annotationmetadata importingClassmetadata);
}
该接口主要是为了导入@Configuration的配置项,而DeferredimportSelector是延期导入,当所有的@Configuration都处理过后才会执行。
回过头来我们看一下AutoConfigurationimportSelector的selectimport方法:
@Override
public String[] selectimports(Annotationmetadata annotationmetadata) {
if (!isEnabled(annotationmetadata)) {
return NO_importS;
}
try {
AutoConfigurationmetadata autoConfigurationmetadata = AutoConfigurationmetadataLoader
.loadmetadata(this.beanClassLoader);
AnnotationAttributes attributes = getAttributes(annotationmetadata);
List configurations = getCandidateConfigurations(annotationmetadata,
attributes);
configurations = removeDuplicates(configurations);
configurations = sort(configurations, autoConfigurationmetadata);
Set exclusions = getExclusions(annotationmetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = filter(configurations, autoConfigurationmetadata);
fireAutoConfigurationimportEvents(configurations, exclusions);
return configurations.toArray(new String[configurations.size()]);
}
catch (IOException ex) {
throw new IllegalStateException(ex);
}
}
该方法刚开始会先判断是否进行自动装配,而后会从meta-INF/spring-autoconfigure-metadata.properties读取元数据与元数据的相关属性,紧接着会调用getCandidateConfigurations方法:
protected ListgetCandidateConfigurations(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; }
在这里又遇到我们的老熟人了--SpringFactoryiesLoader, 它会读取meta-INF/spring.factories下的EnableAutoConfiguration的配置,紧接着在进行排除与过滤,进而得到需要装配的类。最后让所有配置在meta-INF/spring.factories下的AutoConfigurationimportListener执行AutoConfigurationimportEvent事件,代码如下:
private void fireAutoConfigurationimportEvents(List二、何时进行自动装配configurations, Set exclusions) { List listeners = getAutoConfigurationimportListeners(); if (!listeners.isEmpty()) { AutoConfigurationimportEvent event = new AutoConfigurationimportEvent(this, configurations, exclusions); for (AutoConfigurationimportListener listener : listeners) { invokeAwareMethods(listener); listener.onAutoConfigurationimportEvent(event); } } } protected List getAutoConfigurationimportListeners() { return SpringFactoriesLoader.loadFactories(AutoConfigurationimportListener.class, this.beanClassLoader); }
在前面的环节里只是最终要确定哪些类需要被装配,在SpringBoot时何时处理这些自动装配的类呢?下面我们简要的分析一下:
2.1、AbstractApplicationContext的refresh方法:
这个方法老生常谈了其中请大家关注一下这个方法:
// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory);
在这里是处理BeanFactoryPostProcessor的,那么我们在来看一下这个接口BeanDefinitionRegistryPostProcessor:
package org.springframework.beans.factory.support;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;
}
该接口继承了BeanFactoryPostProcessor。
2.2、ConfigurationClassPostProcessor 类
该类主要处理@Configuration注解的,它实现了BeanDefinitionRegistryPostProcessor, 那么也间接实现了BeanFactoryPostProcessor,关键代码如下:
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new importAwareBeanPostProcessor(beanFactory));
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//.....省略部分代码
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set candidates = new linkedHashSet(configCandidates);
Set alreadyParsed = new HashSet(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();
Set configClasses = new linkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getimportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
Set alreadyParsedClasses = new HashSet();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getmetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// ....省略部分代码
}
其实这里注释已经很清楚了,我们可以清楚的看到解析每一个@ConfigurationClass的关键类是:ConfigurationClassParser,那么我们继续看一看这个类的parse方法:
public void parse(SetconfigCandidates) { this.deferredimportSelectors = new linkedList (); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getmetadata(), holder.getBeanName()); } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } processDeferredimportSelectors(); }
在这里大家留意一下最后一句processDeferredimportSelectors方法,在这里将会对DeferredimportSelector进行处理,这样我们就和AutoConfigurationSelectimporter结合到一起了:
private void processDeferredimportSelectors() {
List deferredimports = this.deferredimportSelectors;
this.deferredimportSelectors = null;
Collections.sort(deferredimports, DEFERRED_import_COMPARATOR);
for (DeferredimportSelectorHolder deferredimport : deferredimports) {
ConfigurationClass configClass = deferredimport.getConfigurationClass();
try {
String[] imports = deferredimport.getimportSelector().selectimports(configClass.getmetadata());
processimports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getmetadata().getClassName() + "]", ex);
}
}
}
请大家关注这句代码:String[] imports = deferredimport.getimportSelector().selectimports(configClass.getmetadata());在这里deferredimport的类型为DeferredimportSelectorHolder:
private static class DeferredimportSelectorHolder {
private final ConfigurationClass configurationClass;
private final DeferredimportSelector importSelector;
public DeferredimportSelectorHolder(ConfigurationClass configClass, DeferredimportSelector selector) {
this.configurationClass = configClass;
this.importSelector = selector;
}
public ConfigurationClass getConfigurationClass() {
return this.configurationClass;
}
public DeferredimportSelector getimportSelector() {
return this.importSelector;
}
}
在这个内部类里持有了一个DeferredimportSelector的引用,至此将会执行自动装配的所有操作
三、总结1)自动装配还是利用了SpringFactoriesLoader来加载meta-INF/spring.factoires文件里所有配置的EnableAutoConfgruation,它会经过exclude和filter等操作,最终确定要装配的类
2) 处理@Configuration的核心还是ConfigurationClassPostProcessor,这个类实现了BeanFactoryPostProcessor, 因此当AbstractApplicationContext执行refresh方法里的invokeBeanFactoryPostProcessors(beanFactory)方法时会执行自动装配
以上所述是小编给大家介绍的SpringBoot中的自动装配,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!



