美文网首页
Spring refresh函数(2)——Spring Boot

Spring refresh函数(2)——Spring Boot

作者: 雁阵惊寒_zhn | 来源:发表于2022-01-20 22:06 被阅读0次

    目前Spring Boot已经逐渐取代原来基于xml配置的Spring,渐渐成为各大互联网或软件公司的主力框架。为了贴合实际应用,接下来主要以Spring Boot(本文使用1.5.7.RELEASE版本)为基础进行介绍。

    invokeBeanFactoryPostProcessors()函数是在BeanFactory创建之后,Bean创建之前执行,作用是对已经创建的BeanFactory进行后续的操作。其中将Spring Boot中注解的Bean转换为BeanDefinition结构就在这里完成,BeanDefinition结构为之后创建Bean做准备。本文的主题便是探究Spring Boot如何注册BeanDefinition结构。

    从类AbstractApplicationContext的refresh()函数中的invokeBeanFactoryPostProcessors()函数开始我们的主题。

    invokeBeanFactoryPostProcessors(beanFactory);
    

    进入到类PostProcessorRegistrationDelegate的invokeBeanFactoryPostProcessors()函数。

    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    

    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()函数首先会“Invoke BeanDefinitionRegistryPostProcessors first, if any.”,接口BeanDefinitionRegistryPostProcessor的实现类用于注册BeanDefinition,这里传入的是ConfigurationClassPostProcessor对象处理被@Configuration注解的类。

    public static void invokeBeanFactoryPostProcessors(
          ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        //...略去部分代码...
        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
          for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
              priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
              processedBeans.add(ppName);
            }
        }
        sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
        registryPostProcessors.addAll(priorityOrderedPostProcessors);
        invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
        //...略去部分代码...
    }
    
    图片选自我的公众号

    invokeBeanDefinitionRegistryPostProcessors()函数。

    invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);
    

    invokeBeanDefinitionRegistryPostProcessors()函数中的参数ConfigurationClassPostProcessor对象用于注册BeanDefinition。

    private static void invokeBeanDefinitionRegistryPostProcessors(
          Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    
        for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
          postProcessor.postProcessBeanDefinitionRegistry(registry);
        }
    }
    
    图片选自我的公众号

    执行类ConfigurationClassPostProcessor对象的postProcessBeanDefinitionRegistry()方法。

    @Override
    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);
        }
        if (this.factoriesPostProcessed.contains(registryId)) {
          throw new IllegalStateException(
              "postProcessBeanFactory already called on this post-processor against " + registry);
        }
        this.registriesPostProcessed.add(registryId);
    
        processConfigBeanDefinitions(registry);
    }
    

    进入processConfigBeanDefinitions()函数。从函数名就可以看出这个函数是用于操作被@configuration注解的类。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
        //...略去部分代码...
        // Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
        Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
        Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
        do {
          parser.parse(candidates);
          parser.validate();
          //...略去部分代码...
    }
    

    首先创建了ConfigurationClassParser对象将被用于对被@configuration注解的类进行解析使用。

    // Parse each @Configuration class
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    

    具体解析过程在函数parse()中。

    parser.parse(candidates);
    

    进入类ConfigurationClassParser的parse()函数,会看到依据被@configuration注解的类的BeanDefinition的类型选择不同的parse()函数。而if-else逻辑中的parse()函数都会执行processConfigurationClass()函数。

    public void parse(Set<BeanDefinitionHolder> configCandidates) {
        this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();
    
        for (BeanDefinitionHolder holder : configCandidates) {
          BeanDefinition bd = holder.getBeanDefinition();
          try {
            if (bd instanceof AnnotatedBeanDefinition) {
              parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
            }
            else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
              parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
            }
            else {
              parse(bd.getBeanClassName(), holder.getBeanName());
            }
          }
          catch (BeanDefinitionStoreException ex) {
            throw ex;
          }
          catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
          }
        }
    
        processDeferredImportSelectors();
    }
    
    protected final void parse(String className, String beanName) throws IOException {
        MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className);
        processConfigurationClass(new ConfigurationClass(reader, beanName));
    }
    
    protected final void parse(Class<?> clazz, String beanName) throws IOException {
        processConfigurationClass(new ConfigurationClass(clazz, beanName));
    }
    
    protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
        processConfigurationClass(new ConfigurationClass(metadata, beanName));
    }
    

    processConfigurationClass()函数中继续调用doProcessConfigurationClass()函数。

    如果变量sourceClass表示的类存在父类,doProcessConfigurationClass()函数会返回其父类,do-while循环执行。

    我们程序中只有main()方法所在的类是@configuration注解的,而且无父类,当首次进入到processConfigurationClass()方法中,变量sourceClass就是我们自定义的有main()方法的入口类,do-while循环只执行一次。

    protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        //...略去部分代码...
        // Recursively process the configuration class and its superclass hierarchy.
        SourceClass sourceClass = asSourceClass(configClass);
        do {
          sourceClass = doProcessConfigurationClass(configClass, sourceClass);
        }
        while (sourceClass != null);
    
        this.configurationClasses.put(configClass, configClass);
    }
    

    doProcessConfigurationClass()函数根据变量sourceClass表示的类,解析操作注解它的@ComponentScan注解、@Import注解和@ImportResource注解等。

    这里看@ComponentScan注解的处理逻辑。此处存在着递归调用,递归以变量sourceClass为基础,如果扫描@ComponentScan注解描述的路径下其他类仍旧是被@configuration注解的,继续更深的扫描。doProcessConfigurationClass()->parse()->processConfigurationClass()>doProcessConfigurationClass()方法递归调用。

    this.componentScanParser.parse()进行进一步处理。

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
          throws IOException {
        //...略去部分代码...
        // Process any @ComponentScan annotations
        Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
            sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
        if (!componentScans.isEmpty() &&
            !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
          for (AnnotationAttributes componentScan : componentScans) {
            // The config class is annotated with @ComponentScan -> perform the scan immediately
            //处理@ComponentScan注解
            Set<BeanDefinitionHolder> scannedBeanDefinitions =
                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // Check the set of scanned definitions for any further config classes and parse recursively if needed
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
              if (ConfigurationClassUtils.checkConfigurationClassCandidate(
                  holder.getBeanDefinition(), this.metadataReaderFactory)) {
                //这里可能出现递归
                parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
              }
            }
            //...略去部分代码...
    }
    

    进入类ComponentScanAnnotationParser中的parse()函数解析@ComponentScan注解相关的参数,例如excludeFilters,basePackages参数等。创建ClassPathBeanDefinitionScanner对象用于扫描@ComponentScan注解指定的包。

    直接跳到函数最后一行scanner.doScan()。

    public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
        //...略去部分代码...
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
            componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
        //...略去部分代码...
        return scanner.doScan(StringUtils.toStringArray(basePackages));
    }
    

    进入类ClassPathBeanDefinitionScanner中的方法doScan()。

    类ClassPathBeanDefinitionScanner扫描参数basePackages指定包下所有定义的Bean,转换为BeanDefinition后进行注册。参数basePackages是根据@ComponentScan注解的参数进行解析获得的,如果没有在注解中设置,默认就是被@ComponentScan注解的类所在的包。所以我们要把有main()方法的入口类放在最外层的包中,这样就会扫描到我们定义的所有包下的Bean。

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Assert.notEmpty(basePackages, "At least one base package must be specified");
        Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<BeanDefinitionHolder>();
        for (String basePackage : basePackages) {
          //找到包路径下用户定义的Bean
          Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
          //循环依次注册BeanDefinition
          for (BeanDefinition candidate : candidates) {
            ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
            candidate.setScope(scopeMetadata.getScopeName());
            String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
            if (candidate instanceof AbstractBeanDefinition) {
              postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
            }
            if (candidate instanceof AnnotatedBeanDefinition) {
              AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
            }
            if (checkCandidate(beanName, candidate)) {
              BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
              definitionHolder =
                  AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
              beanDefinitions.add(definitionHolder);
              //注册BeanDefinition
              registerBeanDefinition(definitionHolder, this.registry);
            }
          }
        }
        return beanDefinitions;
    }
    

    doScan()方法中的findCandidateComponents()方法先找到参数basePackages路径下用户自定义的Bean,然后定义它们的BeanDefinition结构返回。

    Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
    

    doScan()方法中之后的for循环依次遍历Set<BeanDefinition> BeanDefinition集合结构,方法registerBeanDefinition()对BeanDefinition进行注册。注册过程,如果是新的BeanDefinition就会直接放入到BeanFactory中的一个map结构beanDefinitionMap变量中存储,如果存在旧的BeanDefinition会进行替换。

    registerBeanDefinition(definitionHolder, this.registry);
    

    自此Spring Boot完成了用户自定义Bean的BeanDefinition结构的注册。以后将使用BeanDefinition结构对Bean进行创建。

    相关文章

      网友评论

          本文标题:Spring refresh函数(2)——Spring Boot

          本文链接:https://www.haomeiwen.com/subject/sbjshrtx.html