阿里10年开发大牛带你学习SpringBoot自动配置原理源码剖析

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。

Spring Boot特点

1. 创建独立的Spring应用程序

2. 嵌入的Tomcat,无需部署WAR文件

3. 简化Maven配置

4. 自动配置Spring

5. 提供生产就绪型功能,如指标,健康检查和外部配置

6. 绝对没有代码生成和对XML没有要求配置

安装Spring Boot

从最根本上来讲,Spring Boot就是一些库的集合,它能够被任意项目的构建系统所使用。简便起见,该框架也提供了命令行界面,它可以用来运行和测试Boot应用。框架的发布版本,包括集成的CLI(命令行界面),可以在Spring仓库中手动下载和安装。一种更为简便的方式是使用Groovy环境管理器(Groovy enVironment Manager,GVM),它会处理Boot版本的安装和管理。Boot及其CLI可以通过GVM的命令行gvm install springboot进行安装。在OS X上安装Boot可以使用Homebrew包管理器。为了完成安装,首先要使用brew tap pivotal/tap切换到Pivotal仓库中,然后执行brew install springboot命令。

要进行打包和分发的工程会依赖于像 Maven或 Gradle这样的构建系统。为了简化依赖图,Boot的功能是模块化的,通过导入Boot所谓的“starter”模块,可以将许多的依赖添加到工程之中。为了更容易地管理依赖版本和使用默认配置,框架提供了一个parent POM,工程可以继承它。

SpringBoot 知识点汇总

SpringBoot 自动配置的原理?

首先自动配置是配置

spring-boot-autoconfigure-2.0.4.RELEASE.jar包下MATA-INF下的spring.properties 文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration所对应自动配置类。

其次springBoot启动类中的@springBootApplication隐含的引入了

EnableAutoConfigurationImportSelector;

// 注解链

@SpringBootApplication

=> @EnableAutoConfiguration

=> @Import(EnableAutoConfigurationImportSelector.class)

在SpringApplication的run方法中,会调context = createApplicationContext();在实例化这个

ConfigurableApplicationContext时,不管是AnnotationConfigEmbeddedWebApplicationContext或AnnotationConfigApplicationContext时(这两个类是专门处理Spring注解方式配置的容器,直接依赖于注解作为容器配置信息来源的IoC容器。 AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本,两者的用法以及对注解的处理方式几乎没有什么差别),都会实例化一个AnnotatedBeanDefinitionReader。例如AnnotationConfigEmbeddedWebApplicationContext实例化代码:

public AnnotationConfigEmbeddedWebApplicationContext() {

this.reader = new AnnotatedBeanDefinitionReader(this);

this.scanner = new ClassPathBeanDefinitionScanner(this);

}

这里将构造

AnnotatedBeanDefinitionReader,在AnnotatedBeanDefinitionReader实例化过程中,会向beanFactory注册CommonAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor、ConfigurationClassPostProcessor等:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {

Assert.notNull(registry, "BeanDefinitionRegistry must not be null");

Assert.notNull(environment, "Environment must not be null");

this.registry = registry;

this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

}

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(

BeanDefinitionRegistry registry, Object source) {

DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);

if (beanFactory != null) {

if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {

beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);

}

if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {

beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());

}

}

Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);

if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));

}

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));

}

if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.

if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));

}

// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.

if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition();

try {

def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,

AnnotationConfigUtils.class.getClassLoader()));

}

catch (ClassNotFoundException ex) {

throw new IllegalStateException(

"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);

}

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));

}

if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));

}

if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {

RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);

def.setSource(source);

beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));

}

return beanDefs;

}

也就是说createApplicationContext()完后,beanFactory的beanDefinitionMap会有6个值。

SpringApplication的run方法中,在调用createApplicationContext();后会调用prepareContext(context, environment, listeners, applicationArguments,printedBanner):

private void prepareContext(ConfigurableApplicationContext context,

ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,

ApplicationArguments applicationArguments, Banner printedBanner) {

// ….

// Load the sources

Set<Object> sources = getSources();

Assert.notEmpty(sources, "Sources must not be empty");

load(context, sources.toArray(new Object[sources.size()]));

listeners.contextLoaded(context);

}

getSources()返回的就是new SpringApplication(Application.class)传入的参数,即我们的主类,然后调用了load()方法,在load()中会生成BeanDefinitionLoader实例,并把主类注册到IOC容器中。

OK,到这里即在调用我们熟悉的

AbstractApplicationContext#refresh()前,beanFactory有7个定义好的beanDefinition。

public void refresh() throws BeansException, IllegalStateException {

Object var1 = this.startupShutdownMonitor;

synchronized(this.startupShutdownMonitor) {

this.prepareRefresh();

ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();

this.prepareBeanFactory(beanFactory);

try {

this.postProcessBeanFactory(beanFactory);

this.invokeBeanFactoryPostProcessors(beanFactory);

this.registerBeanPostProcessors(beanFactory);

this.initMessageSource();

this.initApplicationEventMulticaster();

this.onRefresh();

this.registerListeners();

this.finishBeanFactoryInitialization(beanFactory);

this.finishRefresh();

} catch (BeansException var9) {

if (this.logger.isWarnEnabled()) {

this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);

}

this.destroyBeans();

this.cancelRefresh(var9);

throw var9;

} finally {

this.resetCommonCaches();

}

}

}

ConfigurationClassPostProcessor是BeanFactoryPostProcessor的子类,会在Spring容器refresh时,invokeBeanFactoryPostProcessors(beanFactory)方法中调用到。ConfigurationClassPostProcessor会解析到我们的主类,把@Import中的类拿出来,调用它的selectImports()方法。

ConfigurationClassPostProcessor 中ConfigurationClassParser分析配置类时,如果发现注@Import(ImportSelector)的情况,就会创建一个相应的ImportSelector对象, 并调用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 这里 EnableAutoConfigurationImportSelector的导入@Import(EnableAutoConfigurationImportSelector.class) 就属于这种情况,所以ConfigurationClassParser会实例化一个 EnableAutoConfigurationImportSelector 并调用它的 selectImports() 方法。

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {

int registryId = System.identityHashCode(registry);

if (this.registriesPostProcessed.contains(registryId)) {

throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);

} else if (this.factoriesPostProcessed.contains(registryId)) {

throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);

} else {

this.registriesPostProcessed.add(registryId);

this.processConfigBeanDefinitions(registry);

}

} //BeanFactoryPostProcessor接口唯一的方法,被ConfigurationClassPostProcessor实现了;

//该方法中对配置类中的@import中的类进行解析

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {

List<BeanDefinitionHolder> configCandidates = new ArrayList();

String[] candidateNames = registry.getBeanDefinitionNames();

String[] var4 = candidateNames;

int var5 = candidateNames.length;

for(int var6 = 0; var6 < var5; ++var6) {

String beanName = var4[var6];

BeanDefinition beanDef = registry.getBeanDefinition(beanName);

if (!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {

if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));

}

} else if (this.logger.isDebugEnabled()) {

this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);

}

}

if (!configCandidates.isEmpty()) {

configCandidates.sort((bd1, bd2) -> {

int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());

int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());

return Integer.compare(i1, i2);

});

SingletonBeanRegistry sbr = null;

if (registry instanceof SingletonBeanRegistry) {

sbr = (SingletonBeanRegistry)registry;

if (!this.localBeanNameGeneratorSet) {

BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");

if (generator != null) {

this.componentScanBeanNameGenerator = generator;

this.importBeanNameGenerator = generator;

}

}

}

if (this.environment == null) {

this.environment = new StandardEnvironment();

}

ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);

HashSet alreadyParsed = new HashSet(configCandidates.size());

do {

parser.parse(candidates);

parser.validate();

Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());

configClasses.removeAll(alreadyParsed);

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<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));

Set<String> alreadyParsedClasses = new HashSet();

Iterator var12 = alreadyParsed.iterator();

while(var12.hasNext()) {

ConfigurationClass configurationClass = (ConfigurationClass)var12.next();

alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());

}

String[] var23 = newCandidateNames;

int var24 = newCandidateNames.length;

for(int var14 = 0; var14 < var24; ++var14) {

String candidateName = var23[var14];

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());

if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {

sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());

}

if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {

((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();

}

}

}

public void parse(Set<BeanDefinitionHolder> configCandidates) {

this.deferredImportSelectors = new LinkedList();

Iterator var2 = configCandidates.iterator();

while(var2.hasNext()) {

BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();

BeanDefinition bd = holder.getBeanDefinition();

try {

if (bd instanceof AnnotatedBeanDefinition) {

this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());

} else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {

this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());

} else {

this.parse(bd.getBeanClassName(), holder.getBeanName());

}

} catch (BeanDefinitionStoreException var6) {

throw var6;

} catch (Throwable var7) {

throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);

}

}

this.processDeferredImportSelectors();

}

private void processDeferredImportSelectors() {

List<ConfigurationClassParser.DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;

this.deferredImportSelectors = null;

if (deferredImports != null) {

deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);

Map<Object, ConfigurationClassParser.DeferredImportSelectorGrouping> groupings = new LinkedHashMap();

Map<AnnotationMetadata, ConfigurationClass> configurationClasses = new HashMap();

Iterator var4 = deferredImports.iterator();

while(var4.hasNext()) {

ConfigurationClassParser.DeferredImportSelectorHolder deferredImport = (ConfigurationClassParser.DeferredImportSelectorHolder)var4.next();

Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();

ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)groupings.computeIfAbsent(group != null ? group : deferredImport, (key) -> {

return new ConfigurationClassParser.DeferredImportSelectorGrouping(this.createGroup(group));

});

grouping.add(deferredImport);

configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(), deferredImport.getConfigurationClass());

}

var4 = groupings.values().iterator();

while(var4.hasNext()) {

ConfigurationClassParser.DeferredImportSelectorGrouping grouping = (ConfigurationClassParser.DeferredImportSelectorGrouping)var4.next();

grouping.getImports().forEach((entry) -> {

ConfigurationClass configurationClass = (ConfigurationClass)configurationClasses.get(entry.getMetadata());

try {

this.processImports(configurationClass, this.asSourceClass(configurationClass), this.asSourceClasses(entry.getImportClassName()), false); //调用processImports方法

} catch (BeanDefinitionStoreException var5) {

throw var5;

} catch (Throwable var6) {

throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configurationClass.getMetadata().getClassName() + "]", var6);

}

});

}

}

}

private void processImports(ConfigurationClass configClass, ConfigurationClassParser.SourceClass currentSourceClass, Collection<ConfigurationClassParser.SourceClass> importCandidates, boolean checkForCircularImports) {

if (!importCandidates.isEmpty()) {

if (checkForCircularImports && this.isChainedImportOnStack(configClass)) {

this.problemReporter.error(new ConfigurationClassParser.CircularImportProblem(configClass, this.importStack));

} else {

this.importStack.push(configClass);

try {

Iterator var5 = importCandidates.iterator();

while(true) {

while(true) {

while(var5.hasNext()) {

ConfigurationClassParser.SourceClass candidate = (ConfigurationClassParser.SourceClass)var5.next();

Class candidateClass;

if (candidate.isAssignable(ImportSelector.class)) {

candidateClass = candidate.loadClass();

ImportSelector selector = (ImportSelector)BeanUtils.instantiateClass(candidateClass, ImportSelector.class);

ParserStrategyUtils.invokeAwareMethods(selector, this.environment, this.resourceLoader, this.registry);

if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {

this.deferredImportSelectors.add(new ConfigurationClassParser.DeferredImportSelectorHolder(configClass, (DeferredImportSelector)selector));

} else {

String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); //执行@import类的selectImports方法;

Collection<ConfigurationClassParser.SourceClass> importSourceClasses = this.asSourceClasses(importClassNames);

this.processImports(configClass, currentSourceClass, importSourceClasses, false);

}

} else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {

candidateClass = candidate.loadClass();

ImportBeanDefinitionRegistrar registrar = (ImportBeanDefinitionRegistrar)BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);

ParserStrategyUtils.invokeAwareMethods(registrar, this.environment, this.resourceLoader, this.registry);

configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());

} else {

this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());

this.processConfigurationClass(candidate.asConfigClass(configClass));

}

}

return;

}

}

} catch (BeanDefinitionStoreException var15) {

throw var15;

} catch (Throwable var16) {

throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", var16);

} finally {

this.importStack.pop();

}

}

}

}

// selectImports 的具体执行逻辑 注释参考https://blog.csdn.net/andy_zhang2007/article/details/78580980

@Override

public String[] selectImports(AnnotationMetadata annotationMetadata) {

if (!isEnabled(annotationMetadata)) {

return NO_IMPORTS;

}

try {

// 从配置文件中加载 AutoConfigurationMetadata

AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader

.loadMetadata(this.beanClassLoader);

AnnotationAttributes attributes = getAttributes(annotationMetadata);

// 获取所有候选配置类EnableAutoConfiguration

// 使用了内部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的

// META-INF\spring.factories,找出其中key为

// org.springframework.boot.autoconfigure.EnableAutoConfiguration

// 的属性定义的工厂类名称。

// 虽然参数有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的

// 实现 getCandidateConfigurations()中,这两个参数并未使用

List<String> configurations = getCandidateConfigurations(annotationMetadata,

attributes);

// 去重

configurations = removeDuplicates(configurations);

// 排序 : 先按字典序,再按order属性,再考虑注解 @AutoConfigureBefore @AutoConfigureAfter

configurations = sort(configurations, autoConfigurationMetadata);

// 应用 exclusion 属性

Set<String> exclusions = getExclusions(annotationMetadata, attributes);

checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

// 应用过滤器AutoConfigurationImportFilter,

// 对于 spring boot autoconfigure,定义了一个需要被应用的过滤器 :

// org.springframework.boot.autoconfigure.condition.OnClassCondition,

// 此过滤器检查候选配置类上的注解@ConditionalOnClass,如果要求的类在classpath

// 中不存在,则这个候选配置类会被排除掉

configurations = filter(configurations, autoConfigurationMetadata);

// 现在已经找到所有需要被应用的候选配置类

// 广播事件 AutoConfigurationImportEvent

fireAutoConfigurationImportEvents(configurations, exclusions);

return configurations.toArray(new String[configurations.size()]);

}

catch (IOException ex) {

throw new IllegalStateException(ex);

}

}

/**

* Return the auto-configuration class names that should be considered. By default

* this method will load candidates using SpringFactoriesLoader with

* getSpringFactoriesLoaderFactoryClass().

* @param metadata the source metadata

* @param attributes the getAttributes(AnnotationMetadata) annotation

* attributes

* @return a list of candidate configurations

*/

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,

AnnotationAttributes attributes) {

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 SpringFactoriesLoader to load configuration

* candidates.

* @return the factory class

*/

protected Class<?> getSpringFactoriesLoaderFactoryClass() {

return EnableAutoConfiguration.class;

}

/**

* 根据autoConfigurationMetadata信息对候选配置类configurations进行过滤

**/

private List<String> filter(List<String> configurations,

AutoConfigurationMetadata autoConfigurationMetadata) {

long startTime = System.nanoTime();

String[] candidates = configurations.toArray(new String[configurations.size()]);

// 记录候选配置类是否需要被排除,skip为true表示需要被排除,全部初始化为false,不需要被排除

boolean[] skip = new boolean[candidates.length];

// 记录候选配置类中是否有任何一个候选配置类被忽略,初始化为false

boolean skipped = false;

// 获取AutoConfigurationImportFilter并逐个应用过滤

for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {

// 对过滤器注入其需要Aware的信息

invokeAwareMethods(filter);

// 使用此过滤器检查候选配置类跟autoConfigurationMetadata的匹配情况

boolean[] match = filter.match(candidates, autoConfigurationMetadata);

for (int i = 0; i < match.length; i++) {

if (!match[i]) {

// 如果有某个候选配置类不符合当前过滤器,将其标记为需要被排除,

// 并且将 skipped设置为true,表示发现了某个候选配置类需要被排除

skip[i] = true;

skipped = true;

}

}

}

if (!skipped) {

// 如果所有的候选配置类都不需要被排除,则直接返回外部参数提供的候选配置类集合

return configurations;

}

// 逻辑走到这里因为skipped为true,表明上面的的过滤器应用逻辑中发现了某些候选配置类

// 需要被排除,这里排除那些需要被排除的候选配置类,将那些不需要被排除的候选配置类组成

// 一个新的集合返回给调用者

List<String> result = new ArrayList<String>(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<String>(result);

}

/**

* 使用内部工具 SpringFactoriesLoader,查找classpath上所有jar包中的

* META-INF\spring.factories,找出其中key为

* org.springframework.boot.autoconfigure.AutoConfigurationImportFilter

* 的属性定义的过滤器类并实例化。

* AutoConfigurationImportFilter过滤器可以被注册到 spring.factories用于对自动配置类

* 做一些限制,在这些自动配置类的字节码被读取之前做快速排除处理。

* spring boot autoconfigure 缺省注册了一个 AutoConfigurationImportFilter :

* org.springframework.boot.autoconfigure.condition.OnClassCondition

**/

protected List<AutoConfigurationImportFilter> getAutoConfigurationImportFilters() {

return SpringFactoriesLoader.loadFactories(AutoConfigurationImportFilter.class,

this.beanClassLoader);

}

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {

List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;

}

public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {

String factoryClassName = factoryClass.getName();

return (List)loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());

}

private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {

MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader);

if (result != null) {

return result;

} else {

try {

Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");

LinkedMultiValueMap result = new LinkedMultiValueMap();

while(urls.hasMoreElements()) {

URL url = (URL)urls.nextElement();

UrlResource resource = new UrlResource(url);

Properties properties = PropertiesLoaderUtils.loadProperties(resource);

Iterator var6 = properties.entrySet().iterator();

while(var6.hasNext()) {

Entry<?, ?> entry = (Entry)var6.next();

List<String> factoryClassNames = Arrays.asList(StringUtils.commaDelimitedListToStringArray((String)entry.getValue()));

result.addAll((String)entry.getKey(), factoryClassNames);

}

}

cache.put(classLoader, result);

return result;

} catch (IOException var9) {

throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var9);

}

}

}

而loadSpringFactories会扫描所有jar包下的 META‐INF/spring.factories文件,并封装成properties属性对象;并以key-value的形式存放在MultiValueMap对象中,List configurations = 

getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置时,只需要获取key为org.springframework.boot.autoconfigure.EnableAutoConfiguration的list保存的value,然后返回到processImports方法中,最终注册到IOC容器中;整个自动配置结束;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容