因為想要學習Spring cloud,所以需要學習Spring boot。對於Spring boot主要有以下兩點理解:
1.起步依賴
就好比,你要老媽子給你介紹,你只要關注介紹的這個人就好,至於老媽子怎么去托關系找你二大姑啊,三大姨來張羅啊,你都可以不用管了。
相當於是,對於你需要的應用,它架包的傳遞依賴以及兼容性,spring boot都幫你做了,你無需再去各種架包引用,還得看是否兼容,大大提升了開發效率。
2.自動配置
自動配置,主要看classpath有沒有要初始的bean,會自動進行配置,也可以覆蓋自動配置,這里主要使用了spring的條件化配置。
下圖是SpringApplication啟動原理:

圖1
自動配置
@SpringBootApplication主要涉及到以下三個注解:
@Configuration
@ComponentScan
@EnableAutoConfiguration(最重要)
Auto configure的加載:
@EnableAutoConfiguration --> @Import(導入自動配置) -->@EnableAutoConfigurationImportSelector
(由SpringFactoriesLoader.loadFactoryNames加載EnableAutoConfiguration對應的自動配置項)
@Configuration標記的類加載原理:
configuration類的加載主要是ConfigurationClassPostProcessor類的processConfigBeanDefinitions方法
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()) { Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() { public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) { int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition()); int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition()); return i1 < i2?-1:(i1 > i2?1:0); } }); SingletonBeanRegistry sbr = null; if(registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry)registry; if(!this.localBeanNameGeneratorSet && sbr.containsSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator")) { BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator"); this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates); // 一般啟動時,這里就包含了你的啟動類,如DemoApplication HashSet alreadyParsed = new HashSet(configCandidates.size()); do { // 這里進行轉換,對標記了Configuration的類進行搜集(一般是自動配置的類以及它的依賴類), // 像DemoApplication比較特殊,引入了@ComponentScan,所以會將父包下的Configuration類型的類也會進行搜集,所以如果顯示設置配置,可覆蓋自動設置(條件化加載) // 這里的轉換比較復雜,使用了很多的遞歸以及條件依賴(加載A時,先要加載B),暫不做詳細研究,可重新作為另一方面來探討,有興趣的同學可以一起交流,具體流程可參考下圖 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()); } // 這里主要是對每個標記為Configuration的類加載該類下的Bean配置(@Bean方法,ImportedResources(BeanDefinitionReader)引入的,Registrars注冊器引入的) // 如果自身是需要被引用的,首先將自身注冊為bean,再去加載該類的bean配置 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; // 已注冊的bean,判斷是沒有進行轉換的,則進行轉換(candidates判空循環) 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(); } } }
自動配置的類加載過程:

圖2
在processImports方法中,會加載自動配置所對應的類(spring.factories下的配置)。
以上純屬個人理解,如有錯誤,請見諒,如可以請聯系我,讓我把錯誤修正,感謝。
