Spring configures beans in a variety of forms, the first common being configuring them through XML files, and the other being declaring classes through @Configuraion, indicating that they are a configuration file whose essential role is the same as XML, which acts as a carrier for beans.Today, let's talk about Spring's analysis of Configuraion.
Let's start by explaining some of the points of knowledge that go through Spring's initialization.First, the role of BeanFactoryPostProcessor.Allows you to modify the definition of a Bean in the spring container, that is, to modify the BeanDefinition.Second, BeanDefinition RegistryPostProcessor inherits BeanFactoryPostProcessor, demonstrating that he has BeanFactoryPostProcessor capabilities, in addition to providing a way to register a new BeanDefinition.Third, when did Spring handle BeanFactoryPostProcessor?The answer to this question is to look at the implementation of org.springframework.context.support.AbstractApplicationContext#invokeBeanFactoryPostProcessors, which should not be difficult to understand.
With all the above points in mind, let's start with our protagonist today: ConfigurationClassPostProcessor.It implements the BeanDefinitionRegistryPostProcessor interface, so it has the ability to register beans itself.Let's look at his life cycle approach, postProcessBeanDefinitionRegistry
@Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { ... processConfigBeanDefinitions(registry); }
There is only one parsing method left in the method, and he is undoubtedly the key to understanding parsing.Let's focus on the following
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>(); String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); //Focus 1 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)) { //Focus 2 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 Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() { @Override 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; } }); // Detect any custom bean name generation strategy supplied through the enclosing application context SingletonBeanRegistry singletonRegistry = null; if (registry instanceof SingletonBeanRegistry) { singletonRegistry = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) { BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR); this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } // 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 { //Focus 3 parser.parse(candidates); parser.validate(); Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(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()); } //Focus 4 this.reader.loadBeanDefinitions(configClasses); alreadyParsed.addAll(configClasses); candidates.clear(); if (registry.getBeanDefinitionCount() > candidateNames.length) { String[] newCandidateNames = registry.getBeanDefinitionNames(); Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames)); Set<String> alreadyParsedClasses = new HashSet<String>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } for (String candidateName : newCandidateNames) { if (!oldCandidateNames.contains(candidateName)) { BeanDefinition beanDef = registry.getBeanDefinition(candidateName); if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) && !alreadyParsedClasses.contains(beanDef.getBeanClassName())) { candidates.add(new BeanDefinitionHolder(beanDef, candidateName)); } } } candidateNames = newCandidateNames; } } while (!candidates.isEmpty()); // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes if (singletonRegistry != null) { if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) { singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry()); } } if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) { ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache(); } }
First let's look at Focus 1, getting a specific BeanDefinition by name from BeanDefinitionRegistry. Then we go through two judgments, ConfigurationClassUtils.isFullConfigurationClass and ConfigurationClassUtils.isLiteConfigurationClass
Their implementation is based on a comparison of the string and the value in BeanDefinition's key for org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass, which can be ignored here and discussed later.Now let's look at Focus 2, how spring determines that this Bean is a Configaration, so let's look at ConfigurationClassUtils.checkConfigurationClassCandidate
public static boolean checkConfigurationClassCandidate(BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) { String className = beanDef.getBeanClassName(); if (className == null) { return false; } AnnotationMetadata metadata; if (beanDef instanceof AnnotatedBeanDefinition && className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) { // Can reuse the pre-parsed metadata from the given BeanDefinition... metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata(); } else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) { // Check already loaded Class if present... // since we possibly can't even load the class file for this Class. Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass(); metadata = new StandardAnnotationMetadata(beanClass, true); } else { try { MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className); metadata = metadataReader.getAnnotationMetadata(); } catch (IOException ex) { if (logger.isDebugEnabled()) { logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex); } return false; } } if (isFullConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL); } else if (isLiteConfigurationCandidate(metadata)) { beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE); } else { return false; } // It's a full or lite configuration candidate... Let's determine the order value, if any. Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName()); if (orderAttributes != null) { beanDef.setAttribute(ORDER_ATTRIBUTE, orderAttributes.get(AnnotationUtils.VALUE)); } return true; }
The first half of this approach is to get the AnnotationMetadata for this Bean.The isFullConfigurationCandidate and isLiteConfigurationCandidate are then used to determine whether a corresponding key-value pair needs to be added to BeanDeflection, where the key is defined as the org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass mentioned in Focus 1.So see exactly how it is judged
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) { return metadata.isAnnotated(Configuration.class.getName()); }
If there is a @Configuration annotation on the class, it is a Full configuration class.
public static boolean isLiteConfigurationCandidate(AnnotationMetadata metadata) { // Do not consider an interface or an annotation... if (metadata.isInterface()) { return false; } // Any of the typical annotations found? for (String indicator : candidateIndicators) { if (metadata.isAnnotated(indicator)) { return true; } } // Finally, let's look for @Bean methods... try { return metadata.hasAnnotatedMethods(Bean.class.getName()); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex); } return false; } }
If it's an interface, then it's not a simplified (Lite) configuration class. If the class has annotations defined in the candidateIndicators Set (@Component, @ComponentScan, @Import, @ImportResource), then it's a simplified configuration class. If it's not, then the @Bean annotation-decorated method is also a simplified configuration class.OK, so far we can see how Spring judges a configuration class, then we store it in the collection of configCandidates, BeanDefinitionHolder, for the next step.With this collection, we can now create an instance parser of type ConfigurationClassParser for parsing a configuration file.Let's look at Focus 3, the implementation of the parse method.
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 (Exception ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } processDeferredImportSelectors(); }
Start by creating a LinkedList to hold DeferredImportSelectorHolder, and the method ends up working on this.The intermediate process is the specific parsing process, let's take a look.parse has a lot of song overloads, but ultimately it looks to create an instance of ConfigurationClass type based on the entries and use the processConfigurationClass to handle this instance of ConfigurationClass type.Let's keep watching
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException { if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) { return; } ... // 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); }
The first action is to process the condition comment (@Conditional), and if the definition of the condition in the condition comment is not met, go back without doing the following.Convert data of ConfigurationClass configClass type to SourceClass sourceClass = asSourceClass(configClass);
SorceClass of type followed by doProcessConfigurationClass.
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Recursively process any member (nested) classes first //Focus a processMemberClasses(configClass, sourceClass); // Process any @PropertySource annotations //Focus b for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Process any @ComponentScan annotations //Focus c AnnotationAttributes componentScan = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ComponentScan.class); if (componentScan != null && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) { // The config class is annotated with @ComponentScan -> perform the scan immediately 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 necessary for (BeanDefinitionHolder holder : scannedBeanDefinitions) { if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) { parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName()); } } } // Process any @Import annotations //Focus d processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any // Focus e @ImportResource annotations if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) { AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); String[] resources = importResource.getAliasedStringArray("locations", ImportResource.class, sourceClass); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Process individual // Focus f @Bean methods Set<MethodMetadata> beanMethods = sourceClass.getMetadata().getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces // Focus g for (SourceClass ifc : sourceClass.getInterfaces()) { beanMethods = ifc.getMetadata().getAnnotatedMethods(Bean.class.getName()); for (MethodMetadata methodMetadata : beanMethods) { if (!methodMetadata.isAbstract()) { // A default method or other concrete method on a Java 8+ interface... configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } } } // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (!superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) { this.knownSuperclasses.put(superclass, configClass); // Superclass found, return its annotation metadata and recurse return sourceClass.getSuperClass(); } } // No superclass -> processing is complete return null; }
A meal that parses the labels of the notes is about to take place.First, look at focus a and resolve member classes (internal classes)
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { for (SourceClass memberClass : sourceClass.getMemberClasses()) { if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { processConfigurationClass(memberClass.asConfigClass(configClass)); } finally { this.importStack.pop(); } } } } }
Find all the internal classes and iterate to determine if the internal class is a profile class or if it is a call to the method processConfigurationClass that handles the profile.Now that the internal classes are finished, let's look at Focus b and how to handle the @PropertySources annotation.If there is a @PropertySources annotation on the Configration class, the processPropertySource method is called to process
private void processPropertySource(AnnotationAttributes propertySource) throws IOException { String name = propertySource.getString("name"); String[] locations = propertySource.getStringArray("value"); boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound"); Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required"); for (String location : locations) { try { String resolvedLocation = this.environment.resolveRequiredPlaceholders(location); Resource resource = this.resourceLoader.getResource(resolvedLocation); ResourcePropertySource rps = (StringUtils.hasText(name) ? new ResourcePropertySource(name, resource) : new ResourcePropertySource(resource)); addPropertySource(rps); } catch (IllegalArgumentException ex) { // from resolveRequiredPlaceholders if (!ignoreResourceNotFound) { throw ex; } } catch (FileNotFoundException ex) { // from ResourcePropertySource constructor if (!ignoreResourceNotFound) { throw ex; } } } }
The operation is simple: get the path of the configuration file from the value field in the comment, get the object of type ResourcePropertySource from the path, which contains the data in the property file that has been loaded successfully, then call the addPropertySource method to add the configuration property to the Enviroment.After the property file has been processed successfully, let's look at Focus c. All he has to do is to process the @ComponentScan annotation, which is designed to contain a lot of content and is described in more detail in a later article. Here's just a brief description of what he's doing: get an @ComponentScan instance first, put it in the componentScanParser parser, and get a new Bea scanned forNDefinition, check again if the newly added beans have Configration type, and if so, continue to call the parse method to resolve the configuration.Now that the @ComponentScan comment is resolved, let's look at Focus d, how he parsed the @Import comment.
First let's see how he collects Import notes
private Set<SourceClass> getImports(SourceClass sourceClass) throws IOException { Set<SourceClass> imports = new LinkedHashSet<SourceClass>(); Set<SourceClass> visited = new LinkedHashSet<SourceClass>(); collectImports(sourceClass, imports, visited); return imports; } private void collectImports(SourceClass sourceClass, Set<SourceClass> imports, Set<SourceClass> visited) throws IOException { if (visited.add(sourceClass)) { for (SourceClass annotation : sourceClass.getAnnotations()) { String annName = annotation.getMetadata().getClassName(); if (!annName.startsWith("java") && !annName.equals(Import.class.getName())) { collectImports(annotation, imports, visited); } } imports.addAll(sourceClass.getAnnotationAttributes(Import.class.getName(), "value")); } }
Get all the annotations from the configuration class and iterate through each one. If the annotation class does not start with java or @Import, continue underestimating the search. Finally, put the value of the value found in the Import annotation into the imports collection. Of course, the final return is definitely the imports collection, so the search process is recursive @Import search.Find specific resources to import, and let's see how he handles them
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException { if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { for (SourceClass candidate : importCandidates) { if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); invokeAwareMethods(selector); if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) { // Candidate class is an ImportBeanDefinitionRegistrar -> // delegate to it to register additional bean definitions Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); invokeAwareMethods(registrar); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Exception ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
There are actually three cases you can clearly see, the first imported class is of type ImportSelector.Instantiate this class with reflection, then inject some that should be injected into it. If it's of the DeferredImportSelector type, put it in the deferredImportSelectors collection, which we declared at the beginning of the article and review at the beginning.If this is not the case, call the selectImports method to get the classes that need to be imported, then continue to recursively import this method.The second is the ImportBeanDefinitionRegistrar type, which uses reflection to initialize, then injects the property, and then calls configClass.addImportBeanDefinitionRegistrar to add it.The last case imports a configuration file Configration class that calls the processConfigurationClass method directly for processing.The @Import comment is almost finished.Then let's look at Focus e and work with the @ImportResource annotation.This operation is also simple, if there is an @ImportResource annotation on the configuration question class, get the value in the locations field, get the true path by parsing placeholders, etc., and add it to the configClass by addImportedResource.Next, what we're going to do is @Bean. Take a look at Focus f. Get all the methods declared with the @Bean annotation, and use the addBeanMethod method to encapsulate objects of type BeanMethod into configClass.spring also supports the default method for java8, taking a look at Focus g to get all the interfaces on the configuration class, which will also be added to the configClass if the methods in the interface are decorated with the @Bean annotation.In another section, we mentioned deferredImportSelectors, a collection of deferred ImportSelectors, because data was added to this combination in the process above, and finally we looked at how he handled org.springframework.context.annotation.ConfigurationClassParser#processDeferredImportSelectors
private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Exception ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }
It's not so different from normal processing, probably to delay execution.Get all the classes you want to import, then call the processImports method for a real import.OK, let's go through the process of parsing, parsing all the notes in this class, and putting some data in the configClass is unused.Next let's see where he used it.Take a look at Focus 4 of org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions to create a reader that can be used to load BeanDefinition through a configured ConfigurationClass
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) { String beanName = configClass.getBeanName(); if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) { this.registry.removeBeanDefinition(beanName); } this.importRegistry.removeImportingClassFor(configClass.getMetadata().getClassName()); return; } if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
RegiserBeanDefinitionForImportedConfiguration Class, loadBeanDefinitionsForBeanMethod, loadBeanDefinitionsFromImportedResources, loadBeanDefinitionsFromRegistrars inside register this Configuration as BeanDefinition, change the method using the @Bean comment in the configuration file into BeanDefinition, and configure the ImportResource inFile load parsing, loading the appropriate beans from the resource file, and finally calling the registerBeanDefinitions method of the ImportBeanDefinitionRegistrar type object in the Config class to implement their internal registration logic.
Today I talked a lot and finally finished processing the @Configuration comment. I hope I can help my friends who need it.