Brief Analysis of Springboot--Container Refresh Process

Keywords: Programming Spring Session REST SpringBoot

First, learn about the various post processor extensions

(1) BeanFactoryPostProcessor - bean factory post-processing

Once the BeanFactory standard has been initialized (all BeanDefinition s have been registered after package scanning), this BeanFactory can be postprocessed.

(2) BeanDefinitionRegistryPostProcessor - bean Definition Registry Post Processor

The subinterface of BeanFactoryPostProcessor has an additional postProcessBeanDefinitionRegistry method, which allows BeanDefinitionRegistry (beanDefinition Registry) to be postprocessed before the Bean is instantiated.

(3) BeanPostProcessor - bean Post Processor

Provides extension points for postprocessing instantiated beans.Typically used for reprocessing beans that will be instantiated into containers.

(4) MergedBeanDefinitionPostProcessor - Consolidated Bean Definition Post Processor

Subinterface to BeanPostProcessor, with one more postProcessMergedBeanDefinition (RootBeanDefinition beanDefinition, Class<?> BeanType, String BeanName) method for postprocessing merged Bean definitions.

2. Container Refresh Process

(1) Main Code

//The refresh method that eventually calls to the AbstractApplicationContext
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        // Prepare this context for refreshing.
        // Preprocessing before initialization, initializing PropertySources inside Environment (guess what's inside webXML), nothing under debug
        prepareRefresh();

        // Tell the subclass to refresh the internal bean factory.
        //  Get the BeanFactory and return directly the previously initialized beanFactory with only a SerializationId set
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        // Prepare the bean factory for use in this context.
        // 3. Preprocessing configuration for BeanFactory
	//(1) The ApplicationContextAwareProcessor, a Bean post-processor, is registered in the container to handle beans that implement the XXXAware interface and call its setXXX method.
	//(2) Ignore some auto-injection and add some support for auto-injection, why ignore these auto-injection levers, because when the Auto-injection mode of the beanDefinition is 1 (injected by the name of the setXXX method) and 2 (injected automatically by the return value type of the setXXX method), if auto-injection takes effect, the setXXX method of the Bean will be auto-injected, so as to avoidConflict with XXXAware interface, so ignored.
	//(3) Add some auto-injection support, including BeanFactory, ResourceLoader, ApplicationEventPublisher, ApplicationContext.
	//(4) The new ApplicationListenerDetector(this) is registered with the container as a Bean postprocessor to collect all beans that implement the ApplicationListener interface and collect them into a collection in the container.
        prepareBeanFactory(beanFactory);

        try {
            // Allows post-processing of the bean factory in context subclasses.
            // 4. Prepare post-processing after BeanFactory is complete
	    //Take the servlet environment as an example:
	    //(1) A bean's postprocessor was added to handle ServletContextAware and ServletConfigAware for injection into ServletContext and ServletConfig.
	    //(2) Register the Scope with the container, which describes how the Spring container creates a new Bean instance, where Request and Session Scopes are registered and ServletRequest, ServletResponse, HttpSession, WebRequest are registered for automatic assembly.
	    //(3) A package scan is performed when it is determined that the container's basePackages property is not null (but not here under debug).
	    //(4) Register the container if the annotatedClasses property is not null (not executed under debug).
            postProcessBeanFactory(beanFactory);

            // Invoke factory processors registered as beans in the context.
            // 5. Perform post-processor after BeanFactory creation,
			// In this step, the ConfigurationClassPostProcessor, a bd postprocessor, is processed to complete all bd registration
            invokeBeanFactoryPostProcessors(beanFactory);

            // Register bean processors that intercept bean creation.
            // 6. Register Bean's Postprocessor
            registerBeanPostProcessors(beanFactory);

            // Initialize message source for this context.
            // 7. Initialize MessageSource
            initMessageSource();

            // Initialize event multicaster for this context.
            // 8. Initialize event dispatcher
            initApplicationEventMulticaster();

            // Initialize other special beans in specific context subclasses.
            // 9. Subclass polymorphic onRefresh
            onRefresh();

            // Check for listener beans and register them.
            // 10. Register listeners
            registerListeners();
            //So far, BeanFactory has been created
            // Instantiate all remaining (non-lazy-init) singletons.
            // 11. Initialize all remaining singleton beans
            finishBeanFactoryInitialization(beanFactory);
            // Last step: publish corresponding event.
            // 12. Complete container creation
            finishRefresh();
        }

        catch (BeansException ex) {
            if (logger.isWarnEnabled()) {
                logger.warn("Exception encountered during context initialization - " +
                        "cancelling refresh attempt: " + ex);
            }
            // Destroy already created singletons to avoid dangling resources.
            destroyBeans();
            // Reset 'active' flag.
            cancelRefresh(ex);
            // Propagate exception to caller.
            throw ex;
        }

        finally {
            // Reset common introspection caches in Spring's core, since we
            // might not ever need metadata for singleton beans anymore...
            // 13. Clear Cache
            resetCommonCaches();
        }
    }
}

(2) Core points

1.prepareBeanFactory(beanFactory)-BeanFactory preprocessing configuration

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   // Tell the internal bean factory to use the context's class loader etc.
   // Set class loader, expression parser for BeanFactory, etc.
   beanFactory.setBeanClassLoader(getClassLoader());
   beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
   beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

   // Configure the bean factory with context callbacks.
   //  Configure a BeanPostProcessor that implements the following methods for callback of Aware beans
   beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	// Configuring ignoreDependencyInterface means that these types of auto-assembly are not valid, but can still be assembled when @Autowired injection is tested, so this means to avoid other BDS having auto-injection set, that is, AutowireMode, instead of dependency injection using the @Autowired annotation.
   beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
   beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
   beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
   beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
   beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

   // BeanFactory interface not registered as resolvable type in a plain factory.
   // MessageSource registered (and found for autowiring) as a bean.
   // Support for automatic injection
   beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
   beanFactory.registerResolvableDependency(ResourceLoader.class, this);
   beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
   beanFactory.registerResolvableDependency(ApplicationContext.class, this);

   // Register early post-processor for detecting inner beans as ApplicationListeners.
   // Configure a component that can load all listeners
   beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

   // Detect a LoadTimeWeaver and prepare for weaving, if found.
   if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
       beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
       // Set a temporary ClassLoader for type matching.
       beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
   }

   // Register default environment beans.
   // Registered default runtime environment, system configuration properties, system environment information
   if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
   }
   if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
       beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
   }
}

There are four main things to do here:

  1. ApplicationContextAwareProcessor is registered with the container as a Bean post-processor that handles beans that implement the XXXAware interface and calls its setXXX method.
  2. Ignore some auto-injection and add some support for auto-injection, why ignore these auto-injection levers, because when the beanDefinition's Auto-injection mode is 1 (injection by setXXX method name) and 2 (auto-injection by setXXX method return type), if auto-injection takes effect, the Bean's setXXX method will be auto-injected, so to avoid and XXXAware interface conflict is ignored.
  3. Add some auto-injection support, including BeanFactory, ResourceLoader, ApplicationEventPublisher, ApplicationContext.
  4. A new ApplicationListenerDetector(this) is registered with the container as a Bean postprocessor that collects all beans that implement the ApplicationListener interface and into a collection in the container.

2. postProcessBeanFactory - Post-processing to prepare BeanFactory for completion

Take the servlet as an example: The ApplicationContext implementation here is actually the AnnotationConfigServlet WebServerApplicationContext.In the AnnotationConfigServletWebServerApplicationContext class, this method is primarily complete:

  1. A bean's postprocessor processing ServletContextAware and ServletConfigAware is registered with the container to inject ServletContext and ServletConfig.
  2. Register Scope with the container, which describes how the Spring container creates a new Bean instance. Request and Session Scopes are registered here and ServletRequest, ServletResponse, HttpSession, WebRequest are registered for automatic assembly.
  3. A package scan is performed when it is determined that the container's basePackages property is not null (but not here under debug).
  4. When it is determined that the annotatedClasses property of the container is not null, it is also registered (not executed under debug).

3.invokeBeanFactoryPostProcessors(beanFactory) - Post Processor after BeanFactory creation is executed

Code:

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    // Execute BeanFactory Post Processor
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

    // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
        beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
        beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    }
}

Enter PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()):

public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

    // Invoke BeanDefinitionRegistryPostProcessors first, if any.
    //Used to store processedBeans that have been executed
    Set<String> processedBeans = new HashSet<>();

    // To determine the type of BeanFactory here, the BeanFactory created by the default SpringBoot is DefaultListableBeanFactory
    // This class implements the BeanDefinitionRegistry interface, then this if structure must be advanced
    if (beanFactory instanceof BeanDefinitionRegistry) {
        BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<>();
        List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<>();
		//Traverse the BeanFactoryPostProcessor postprocessor that has been registered with the beanFactory, then categorize it as regular PostProcessors and registryProcessors
        for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
            if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                BeanDefinitionRegistryPostProcessor registryProcessor =
                        (BeanDefinitionRegistryPostProcessor) postProcessor;
                registryProcessor.postProcessBeanDefinitionRegistry(registry);
                registryProcessors.add(registryProcessor);
            }
            else {
                regularPostProcessors.add(postProcessor);
            }
        }

        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        // Separate between BeanDefinitionRegistryPostProcessors that implement
        // PriorityOrdered, Ordered, and the rest.
     	//This currentRegistryProcessors variable is used to execute methods in stages because of the existence of the PriorityOrdered and Ordered interfaces
        List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
  
        // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
        // First, call BeanDefinitionRegistryPostProcessors that implement the PriorityOrdered interface and add them to processedBeans
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
		//sort
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        //Add to registryProcessors
        registryProcessors.addAll(currentRegistryProcessors);
        //implement
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
        // Next, call BeanDefinitionRegistryPostProcessors, which implements the Ordered interface.
        postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
        for (String ppName : postProcessorNames) {
            if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                processedBeans.add(ppName);
            }
        }
		//sort
        sortPostProcessors(currentRegistryProcessors, beanFactory);
        //Add to registryProcessors
		registryProcessors.addAll(currentRegistryProcessors);
		//implement
        invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
        currentRegistryProcessors.clear();

        // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
        // Finally, call all other BeanDefinitionRegistryPostProcessor
        boolean reiterate = true;
        while (reiterate) {
            reiterate = false;
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName)) {
                    currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                    reiterate = true;
                }
            }
			//Sort Add Execution
            sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
        }

        // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
        // Callback postProcessBeanFactory method for all BeanFactoryPostProcessor s
        invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        // Callback BeanDefinitionRegistryPostProcessor's postProcessBeanFactory method first
        // Call BeanFactoryPostProcessor's postProcessBeanFactory method again
    }

    // If BeanFactory does not implement the BeanDefinitionRegistry interface, proceed to the following code flow
    else {
        // Invoke factory processors registered with the context instance.
        // Calls the factory processor registered in the context instance.
        invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    }

    // The following section calls back BeanFactoryPostProcessor in much the same way as above
  
    // Do not initialize FactoryBeans here: We need to leave all regular beans
    // uninitialized to let the bean factory post-processors apply to them!
    String[] postProcessorNames =
            beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

    // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    // Ordered, and the rest.
    List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
    List<String> orderedPostProcessorNames = new ArrayList<>();
    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
    for (String ppName : postProcessorNames) {
        if (processedBeans.contains(ppName)) {
            // skip - already processed in first phase above
        }
        else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
            priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
        }
        else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
            orderedPostProcessorNames.add(ppName);
        }
        else {
            nonOrderedPostProcessorNames.add(ppName);
        }
    }

    // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

    // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : orderedPostProcessorNames) {
        orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    sortPostProcessors(orderedPostProcessors, beanFactory);
    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

    // Finally, invoke all other BeanFactoryPostProcessors.
    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
    for (String postProcessorName : nonOrderedPostProcessorNames) {
        nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    }
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

    // Clear cached merged bean definitions since the post-processors might have
    // modified the original metadata, e.g. replacing placeholders in values...
    // Clean Cache
    beanFactory.clearMetadataCache();
}

The code above is a bit long The main things to do are:

  1. The first step is to get the beanFactoryPostProcessors that have been registered with the container (as opposed to the beanDifinitionMap), which use the beanFactoryPostProcessors in the container as a variable rather than from the beanDefinition, and to filter the beanFactoryPostProcessors that implement the BeanDefinitionRegistryPostProcessor interface and execute its postProcessBeanDefinitionRegistry method.
  2. The second step takes the beans of type BeanDefinitionRegistryPostProcessor in the registered beanDefinition in the container, filters those that implement the PriorityOrdered interface, sorts them, and calls back their postProcessBeanDefinitionRegistry.This executes the most important Configuration ClassPostProcessor, which handles the configraution annotations in the current beandifinitonMap, such as handling @Component ,@ComponentScan ,@Import ,@ImportResource, @PropertySource, @ComponentScan, @Import, @ImportResource, @Bean annotation, register all beanDefinition s, and expand on this ConfigurationClassPostProcessor later.
  3. The third step, getting beans of type BeanDefinitionRegistryPostProcessor in a registered beanDefinition in a container, sorts them according to whether the PriorityOrdered interface Ordered interface is implemented (roughly in the order PriorityOrdered preferred Ordered does not implement the interface, the same interface is ordered by method return value), and then calls its postProcessBeanDefinitionRegistry method.
  4. The fourth step executes the postBeanFactory method for all bean s of type DefinitionRegistryPostProcessor above.
  5. Step 5 For a beanFactoryPostProcessor within an ApplicationContext (as opposed to a beanDifinitionMap), which uses the beanFactoryPostProcessors variable store instead of the beanDefinition store, does not belong to the BeanDefinitionRegistryPostProcessor interface (that is, just BeanFactoryProcessor), call its postBeanFactory method.
  6. The sixth step, calling the postBeanFactory method of all other BeanFactoryPostProcessor s, also resolves the PriorityOrdered and Ordered interfaces.

Next, let's focus on the source code for the ConfigurationClassPostProcessor executed in the second step. It's not expanded in detail and the approximate process has been written to the comment:

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

This means getting the container Id, getting if it has been called, and if not, continuing with processConfigBeanDefinitions.Take a look at the processConfigBeanDefinitions(registry) method:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    // Determine configuration classes and components
	//The configurationClass value of bd with the @Configuration annotation is set to full,
	//Method with @Component, @ComponentScan, @Import, @ImportResource comment or method added with @Bean
	//(You just collected the methods with bean s, but did not register bd) Set the configurationClass value to lite and add to configCandidates
    for (String beanName : candidateNames) {
        BeanDefinition beanDef = registry.getBeanDefinition(beanName);
        if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
                ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
            if (logger.isDebugEnabled()) {
                logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
            }
        }
        else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // Return immediately if no @Configuration classes were found
    if (configCandidates.isEmpty()) {
        return;
    }

    // Sort by previously determined @Order value, if applicable
    // Sort configuration classes
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // Detect any custom bean name generation strategy supplied through the enclosing application context
    // Load Get BeanNameGenerator
    SingletonBeanRegistry sbr = null;
    if (registry instanceof SingletonBeanRegistry) {
        sbr = (SingletonBeanRegistry) registry;
        if (!this.localBeanNameGeneratorSet) {
            BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
            if (generator != null) {
                this.componentScanBeanNameGenerator = generator;
                this.importBeanNameGenerator = generator;
            }
        }
    }

    if (this.environment == null) {
        this.environment = new StandardEnvironment();
    }

    // Parse each @Configuration class
    // Initialize Configuration Class Parser
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);
	//Set of configuration classes that need to be resolved
    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    //Resolved collection of configuration classes
	Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    do {
        // Resolving configuration classes, the most important method
		//Sort configCandidates by @Order and iterate through the normal recursive resolution parent class.
		//The @PropertySource, @ComponentScan, @Import, @ImportResource, @Bean annotations need to be resolved (annotation This step has not fully registered the scanned components with Bd,
		//It simply registers the bd scanned by the package and implements the bd of the ImportBeanDefinitionRegistrar or ImportSelector interface when processing the @Import annotation.
		//And the nested configuration class of a class is handled here first)
        parser.parse(candidates);
		//check
        parser.validate();
        Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
        configClasses.removeAll(alreadyParsed);

        // Read the model and create bean definitions based on its content
        if (this.reader == null) {
            this.reader = new ConfigurationClassBeanDefinitionReader(
                    registry, this.sourceExtractor, this.resourceLoader, this.environment,
                    this.importBeanNameGenerator, parser.getImportRegistry());
        }
        //Resolve content in configuration class
		//Classes registered with the @Import, @Bean annotations and configuration files introduced by processing the @ImportResource annotations are parsed into BeanDefinition and registered in BeanDefinitionMap.
        this.reader.loadBeanDefinitions(configClasses);
        alreadyParsed.addAll(configClasses);
        candidates.clear();
        if (registry.getBeanDefinitionCount() > candidateNames.length) {
		   //Current bdNames
            String[] newCandidateNames = registry.getBeanDefinitionNames();
			//bdNames before last resolution
            Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
			//bdNames for this parse
            Set<String> alreadyParsedClasses = new HashSet<>();
            for (ConfigurationClass configurationClass : alreadyParsed) {
                alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
            }
			//Traverse through the current bdNames, add to candidates if it is not a previous configuration class and has not been resolved, and resolve again in the next loop
            for (String candidateName : newCandidateNames) {
                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());

    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
    // Register ImportRegistry as a Bean to support ImportAware and @Configuration classes
    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
        sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
    }

    // Clear Cache
    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
        // Clear cache in externally provided MetadataReaderFactory; this is a no-op
        // for a shared cache since it'll be cleared by the ApplicationContext.
        ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
    }
}

4.registerBeanPostProcessors(beanFactory) - Registered bean postprocessor (including MergedBeanDefinitionPostProcessor)

The registration logic is similar to that of a registered beanFactoryPostProcessor, where the order of registration determines the priorityOrdered and Ordered interfaces and registers the MergedBeanDefinitionPostProcessor before registering the beanFactoryPostProcessor.

There are two MergedBeanDefinitionPostProcessor s, one is AutowiredAnnotationBeanPostProcessor and the other is ApplicationListenerDetector.

-------------------------------------------------------- Sleepy, not to be continued

Posted by SemiApocalyptic on Sun, 01 Mar 2020 10:54:34 -0800