因为想要学习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下的配置)。
以上纯属个人理解,如有错误,请见谅,如可以请联系我,让我把错误修正,感谢。