阿里10年開發(fā)大牛帶你學(xué)習(xí)SpringBoot自動(dòng)配置原理源碼剖析

Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架偷溺,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開發(fā)過(guò)程挺身。該框架使用了特定的方式來(lái)進(jìn)行配置,從而使開發(fā)人員不再需要定義樣板化的配置蒿囤。通過(guò)這種方式从隆,Spring Boot致力于在蓬勃發(fā)展的快速應(yīng)用開發(fā)領(lǐng)域(rapid application development)成為領(lǐng)導(dǎo)者。

Spring Boot特點(diǎn)

1. 創(chuàng)建獨(dú)立的Spring應(yīng)用程序

2. 嵌入的Tomcat果复,無(wú)需部署WAR文件

3. 簡(jiǎn)化Maven配置

4. 自動(dòng)配置Spring

5. 提供生產(chǎn)就緒型功能陈莽,如指標(biāo),健康檢查和外部配置

6. 絕對(duì)沒(méi)有代碼生成和對(duì)XML沒(méi)有要求配置

安裝Spring Boot

從最根本上來(lái)講据悔,Spring Boot就是一些庫(kù)的集合传透,它能夠被任意項(xiàng)目的構(gòu)建系統(tǒng)所使用。簡(jiǎn)便起見(jiàn)极颓,該框架也提供了命令行界面朱盐,它可以用來(lái)運(yùn)行和測(cè)試Boot應(yīng)用〔ぢ。框架的發(fā)布版本兵琳,包括集成的CLI(命令行界面),可以在Spring倉(cāng)庫(kù)中手動(dòng)下載和安裝骇径。一種更為簡(jiǎn)便的方式是使用Groovy環(huán)境管理器(Groovy enVironment Manager躯肌,GVM),它會(huì)處理Boot版本的安裝和管理破衔。Boot及其CLI可以通過(guò)GVM的命令行g(shù)vm install springboot進(jìn)行安裝清女。在OS X上安裝Boot可以使用Homebrew包管理器。為了完成安裝晰筛,首先要使用brew tap pivotal/tap切換到Pivotal倉(cāng)庫(kù)中嫡丙,然后執(zhí)行brew install springboot命令拴袭。

要進(jìn)行打包和分發(fā)的工程會(huì)依賴于像 Maven或 Gradle這樣的構(gòu)建系統(tǒng)。為了簡(jiǎn)化依賴圖曙博,Boot的功能是模塊化的拥刻,通過(guò)導(dǎo)入Boot所謂的“starter”模塊,可以將許多的依賴添加到工程之中父泳。為了更容易地管理依賴版本和使用默認(rèn)配置般哼,框架提供了一個(gè)parent POM,工程可以繼承它惠窄。

SpringBoot 知識(shí)點(diǎn)匯總

SpringBoot 自動(dòng)配置的原理蒸眠?

首先自動(dòng)配置是配置

spring-boot-autoconfigure-2.0.4.RELEASE.jar包下MATA-INF下的spring.properties 文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration所對(duì)應(yīng)自動(dòng)配置類。

其次springBoot啟動(dòng)類中的@springBootApplication隱含的引入了

EnableAutoConfigurationImportSelector;

// 注解鏈

@SpringBootApplication

=> @EnableAutoConfiguration

=> @Import(EnableAutoConfigurationImportSelector.class)

在SpringApplication的run方法中睬捶,會(huì)調(diào)context = createApplicationContext();在實(shí)例化這個(gè)

ConfigurableApplicationContext時(shí)黔宛,不管是AnnotationConfigEmbeddedWebApplicationContext或AnnotationConfigApplicationContext時(shí)(這兩個(gè)類是專門處理Spring注解方式配置的容器,直接依賴于注解作為容器配置信息來(lái)源的IoC容器擒贸。?AnnotationConfigWebApplicationContext是AnnotationConfigApplicationContext的web版本臀晃,兩者的用法以及對(duì)注解的處理方式幾乎沒(méi)有什么差別),都會(huì)實(shí)例化一個(gè)AnnotatedBeanDefinitionReader介劫。例如AnnotationConfigEmbeddedWebApplicationContext實(shí)例化代碼:

public AnnotationConfigEmbeddedWebApplicationContext() {

this.reader = new AnnotatedBeanDefinitionReader(this);

this.scanner = new ClassPathBeanDefinitionScanner(this);

}

這里將構(gòu)造

AnnotatedBeanDefinitionReader徽惋,在AnnotatedBeanDefinitionReader實(shí)例化過(guò)程中,會(huì)向beanFactory注冊(cè)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;

}

也就是說(shuō)createApplicationContext()完后,beanFactory的beanDefinitionMap會(huì)有6個(gè)值誉碴。

SpringApplication的run方法中宦棺,在調(diào)用createApplicationContext();后會(huì)調(diào)用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)傳入的參數(shù),即我們的主類黔帕,然后調(diào)用了load()方法代咸,在load()中會(huì)生成BeanDefinitionLoader實(shí)例,并把主類注冊(cè)到IOC容器中成黄。

OK呐芥,到這里即在調(diào)用我們熟悉的

AbstractApplicationContext#refresh()前,beanFactory有7個(gè)定義好的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的子類思瘟,會(huì)在Spring容器refresh時(shí),invokeBeanFactoryPostProcessors(beanFactory)方法中調(diào)用到闻伶。ConfigurationClassPostProcessor會(huì)解析到我們的主類滨攻,把@Import中的類拿出來(lái),調(diào)用它的selectImports()方法。

ConfigurationClassPostProcessor 中ConfigurationClassParser分析配置類時(shí)铡买,如果發(fā)現(xiàn)注@Import(ImportSelector)的情況更鲁,就會(huì)創(chuàng)建一個(gè)相應(yīng)的ImportSelector對(duì)象霎箍, 并調(diào)用其方法 public String[] selectImports(AnnotationMetadata annotationMetadata), 這里?EnableAutoConfigurationImportSelector的導(dǎo)入@Import(EnableAutoConfigurationImportSelector.class) 就屬于這種情況,所以ConfigurationClassParser會(huì)實(shí)例化一個(gè)?EnableAutoConfigurationImportSelector 并調(diào)用它的 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實(shí)現(xiàn)了漂坏;

//該方法中對(duì)配置類中的@import中的類進(jìn)行解析

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); //調(diào)用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()); //執(zhí)行@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 的具體執(zhí)行邏輯 注釋參考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

// 使用了內(nèi)部工具使用SpringFactoriesLoader,查找classpath上所有jar包中的

// META-INF\spring.factories顶别,找出其中key為

// org.springframework.boot.autoconfigure.EnableAutoConfiguration

// 的屬性定義的工廠類名稱谷徙。

// 雖然參數(shù)有annotationMetadata,attributes,但在 AutoConfigurationImportSelector 的

// 實(shí)現(xiàn) getCandidateConfigurations()中,這兩個(gè)參數(shù)并未使用

List<String> configurations = getCandidateConfigurations(annotationMetadata,

attributes);

// 去重

configurations = removeDuplicates(configurations);

// 排序 : 先按字典序驯绎,再按order屬性完慧,再考慮注解 @AutoConfigureBefore @AutoConfigureAfter

configurations = sort(configurations, autoConfigurationMetadata);

// 應(yīng)用 exclusion 屬性

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

checkExcludedClasses(configurations, exclusions);

configurations.removeAll(exclusions);

// 應(yīng)用過(guò)濾器AutoConfigurationImportFilter,

// 對(duì)于 spring boot autoconfigure剩失,定義了一個(gè)需要被應(yīng)用的過(guò)濾器 :

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

// 此過(guò)濾器檢查候選配置類上的注解@ConditionalOnClass,如果要求的類在classpath

// 中不存在拴孤,則這個(gè)候選配置類會(huì)被排除掉

configurations = filter(configurations, autoConfigurationMetadata);

// 現(xiàn)在已經(jīng)找到所有需要被應(yīng)用的候選配置類

// 廣播事件 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;

}

/**

* 根據(jù)autoConfigurationMetadata信息對(duì)候選配置類configurations進(jìn)行過(guò)濾

**/

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];

// 記錄候選配置類中是否有任何一個(gè)候選配置類被忽略脾歧,初始化為false

boolean skipped = false;

// 獲取AutoConfigurationImportFilter并逐個(gè)應(yīng)用過(guò)濾

for (AutoConfigurationImportFilter filter : getAutoConfigurationImportFilters()) {

// 對(duì)過(guò)濾器注入其需要Aware的信息

invokeAwareMethods(filter);

// 使用此過(guò)濾器檢查候選配置類跟autoConfigurationMetadata的匹配情況

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

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

if (!match[i]) {

// 如果有某個(gè)候選配置類不符合當(dāng)前過(guò)濾器,將其標(biāo)記為需要被排除演熟,

// 并且將 skipped設(shè)置為true鞭执,表示發(fā)現(xiàn)了某個(gè)候選配置類需要被排除

skip[i] = true;

skipped = true;

}

}

}

if (!skipped) {

// 如果所有的候選配置類都不需要被排除,則直接返回外部參數(shù)提供的候選配置類集合

return configurations;

}

// 邏輯走到這里因?yàn)閟kipped為true芒粹,表明上面的的過(guò)濾器應(yīng)用邏輯中發(fā)現(xiàn)了某些候選配置類

// 需要被排除兄纺,這里排除那些需要被排除的候選配置類,將那些不需要被排除的候選配置類組成

// 一個(gè)新的集合返回給調(diào)用者

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

}

/**

* 使用內(nèi)部工具 SpringFactoriesLoader化漆,查找classpath上所有jar包中的

* META-INF\spring.factories估脆,找出其中key為

* org.springframework.boot.autoconfigure.AutoConfigurationImportFilter

* 的屬性定義的過(guò)濾器類并實(shí)例化。

* AutoConfigurationImportFilter過(guò)濾器可以被注冊(cè)到 spring.factories用于對(duì)自動(dòng)配置類

* 做一些限制获三,在這些自動(dòng)配置類的字節(jié)碼被讀取之前做快速排除處理旁蔼。

* spring boot autoconfigure 缺省注冊(cè)了一個(gè) 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會(huì)掃描所有jar包下的 META‐INF/spring.factories文件,并封裝成properties屬性對(duì)象疙教;并以key-value的形式存放在MultiValueMap對(duì)象中棺聊,List configurations =?

getCandidateConfigurations(annotationMetadata, attributes);獲取候選的配置時(shí),只需要獲取key為org.springframework.boot.autoconfigure.EnableAutoConfiguration的list保存的value,然后返回到processImports方法中贞谓,最終注冊(cè)到IOC容器中限佩;整個(gè)自動(dòng)配置結(jié)束;

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市祟同,隨后出現(xiàn)的幾起案子作喘,更是在濱河造成了極大的恐慌,老刑警劉巖晕城,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泞坦,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡砖顷,警方通過(guò)查閱死者的電腦和手機(jī)贰锁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)滤蝠,“玉大人豌熄,你說(shuō)我怎么就攤上這事∥锟龋” “怎么了锣险?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)览闰。 經(jīng)常有香客問(wèn)我芯肤,道長(zhǎng),這世上最難降的妖魔是什么焕济? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任纷妆,我火速辦了婚禮,結(jié)果婚禮上晴弃,老公的妹妹穿的比我還像新娘掩幢。我一直安慰自己,他們只是感情好上鞠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布际邻。 她就那樣靜靜地躺著,像睡著了一般芍阎。 火紅的嫁衣襯著肌膚如雪世曾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天谴咸,我揣著相機(jī)與錄音轮听,去河邊找鬼。 笑死岭佳,一個(gè)胖子當(dāng)著我的面吹牛血巍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播珊随,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼述寡,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼柿隙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鲫凶,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤禀崖,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后螟炫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體波附,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年不恭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了叶雹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡换吧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钥星,到底是詐尸還是另有隱情沾瓦,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布谦炒,位于F島的核電站贯莺,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏宁改。R本人自食惡果不足惜缕探,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望还蹲。 院中可真熱鬧爹耗,春花似錦、人聲如沸谜喊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)斗遏。三九已至山卦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诵次,已是汗流浹背账蓉。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留逾一,地道東北人铸本。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像嬉荆,于是被迫代替她去往敵國(guó)和親归敬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容