Spring boot的启动加载原理

因为想要学习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下的配置)。

  以上纯属个人理解,如有错误,请见谅,如可以请联系我,让我把错误修正,感谢。

posted on 2017-12-13 16:22  zgz2016  阅读(2271)  评论(0编辑  收藏  举报

导航