When we use context to obtain beans, in fact, the bottom layer is the DefaultListableBeanFactory class of operation. This class is mainly divided into two parts:
- Registered bean: parse class and encapsulate it as beanDefinition object;
- Instantiate an object from beanDefinition.
Let's first look at how to save data.
beanDefinition object
Properties in DefaultListableBeanFactory:
// key: the name of the bean // value: BeanDefinition object private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); //Save key: type and value:bean name by type private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64); // Only the single example is saved here private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64); // Names of all bean s private volatile List<String> beanDefinitionNames = new ArrayList<>(256); // The name of the manually added bean // Why is it added manually? Because we can operate context and add our own BeanDefinition, which is added manually and will be added to this set. private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);
Instance object
Always find the parent class from DefaultListableBeanFactory, and you will find DefaultSingletonBeanRegistry
//Bean name bean instance private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); //The class of ObjectFactory is saved private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); //Early exposed bean s are used to solve circular dependencies private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // Name of the instance. private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
If you know where to save the data, you can start to see where to parse the class and encapsulate it as the beandefinitions class. Because spring supports configuration files and annotations. So let's take a look at how to register beans.
ClassPathXmlApplicationContext resolves the configuration file registration bean
We usually use this when creating:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
The configuration file passed in to spring is registered in the container by parsing the configuration inside.
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); // Set the path of the configuration file setConfigLocations(configLocations); if (refresh) { // Call the refresh method. refresh(); } }
Refresh method at org springframework. context. support. Abstractapplicationcontext#refresh(), which has many methods. xml is parsed in the obtainFreshBeanFactory method
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // Refresh the factory and return the factory to refreshBeanFactory(); return getBeanFactory(); }
org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException { // If it already exists, destroy it and recreate it. if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // The instance factory is to create the DefaultListableBeanFactory object DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); // Register the configuration in the configuration file into beanFactory. loadBeanDefinitions(beanFactory); synchronized (this.beanFactoryMonitor) { this.beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions(org.springframework.beans.factory.xml.XmlBeanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null) { reader.loadBeanDefinitions(configLocations); } }
When XmlBeanDefinitionReader is instantiated, beanFactory has been put into. Now the path of the incoming configuration file.
Continue to explore the following methods:
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } }
Resolve tags through namespaces. On the line, under different namespaces
First look at the following under this namespace:
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { // Import tag to import other configuration files. if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } // Alias Tag else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } // bean tag else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } //beans tag else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { // recurse doRegisterBeanDefinitions(ele); } }
importBeanDefinitionResource: used to parse the import tag. The import tag is used to import other configuration files; The internal logic is to get the location data and then use XmlBeanDefinitionReader to parse the path. In fact, it is the logic of analyzing configuration and asking price
processAliasRegistration: resolve the alias tag, resolve the alias, key: bean name, value is the alias, and put it into the alias map.
processBeanDefinition: resolves the bean tag. The data in the bean tag will directly correspond to the properties in beandenition. The property tag will be resolved to PropertyValue and added to bf's property collection. Constructors are similar logic.
doRegisterBeanDefinitions: when parsing the beans tag, it means recursion or calling the same logic. Now what is parsed is the content in the beans tag.
See the resolution of other namespaces:
Parse the corresponding tag.
org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse
public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }
Here we start with different namespaces and different parsers
You can see the corresponding labels by name:
AnnotationConfigBeanDefinitionParser
The code is subsidized. It directly says that it did those things. Some beans are registered. What do these beans do?
ConfigurationClassPostProcessor: used to resolve the configuration class (@ configuration)
Autowired annotation beanpostprocessor: @ Autowired dependency injected processor
CommonAnnotationBeanPostProcessor: @ resource depends on the injected processor
EventListenerMethodProcessor
DefaultEventListenerFactory
The latter two have also been injected. I haven't seen them yet.
AnnotationDrivenBeanDefinitionParser
Two bean s are also registered: these two good analyses are to create an agent and put the method of the agent into one thread for execution.
AsyncAnnotationBeanPostProcessor
ScheduledAnnotationBeanPostProcessor
AnnotationDrivenCacheBeanDefinitionParser
The name is spring's Cache, which is still a registered processor class related to it.
There are two ways of acting. I haven't learned about the aspects. The agent is registered with the class infrastructureasuggestorautoproxycreator. It is specially used to analyze the aspects inside spring. What is inside spring? Role() == BeanDefinition.ROLE_INFRASTRUCTURE
AspectJAutoProxyBeanDefinitionParser
At first glance, it is related to aop. The registration processor is annotation awareaspectjauto proxycreator
ComponentScanBeanDefinitionParser
Scan package processor:
public BeanDefinition parse(Element element, ParserContext parserContext) { String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // The processor that resolves the package name ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
Note: the doScan method of ClassPathBeanDefinitionScanner has been registered with the scanned beans. The registerComponents method contains the functions of the above AnnotationConfigBeanDefinitionParser.
There are other parsers. Just analyze it yourself.
The registered bean of ClassPathXmlApplicationContext has been analyzed: except that the bean tag is a real registered bean, other tags are processors of registered functions.
Let's take a look at how the annotated container registers bean s. Think about it: ClassPathXmlApplicationContext is a registered processor by parsing labels, so annotations must be used to implement the registered processor in the AnnotationConfigApplicationContext.
How do ordinary bean s register? Guess, it should be the scanned annotation.
ClassPathXmlApplicationContext is a configuration file for. Parse the file.
AnnotationConfigApplicationContext: give a class with configuration annotations. Parsing annotations in classes.
AnnotationConfigApplicationContext parsing configuration class
The parameter of ClassPathXmlApplicationContext is the path of the configuration file; Multiple paths can be passed, or other configuration files can be introduced into the import tag in a general file price inquiry;
AnnotationConfigApplicationContext needs to be passed into the configuration class; It can also be transmitted to multiple; But usually only the configuration class of the host will be passed. After that, the annotation in the main configuration class: @ compoentscan; Scan bean s and configuration classes. Then analyze.
public AnnotationConfigApplicationContext(Class<?>... componentClasses) { // Call its own constructor this(); // Register the main configuration class register(componentClasses); // Refresh method refresh(); } //The parameterless constructor creates two objects. public AnnotationConfigApplicationContext() { // Processor for reading annotations this.reader = new AnnotatedBeanDefinitionReader(this); // Processor used to scan bean s this.scanner = new ClassPathBeanDefinitionScanner(this); }
When creating the AnnotatedBeanDefinitionReader object, several beans are registered, which are those registered in the AnnotationConfigBeanDefinitionParser function; Note: the bean ConfigurationClassPostProcessor is used to parse configuration classes.
When creating ClassPathBeanDefinitionScanner, only the scanning conditions are configured.
To learn more about how annotation type containers parse classes and encapsulate them as beanDefinition, first look at this article:
[spring IOC] customization of BeanFactory through BeanFactory postprocessor
Based on the above, take a look at this class: ConfigurationClassPostProcessor. No, it's registered by AnnotatedBeanDefinitionReader.
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor, PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware
It implements BeanDefinitionRegistryPostProcessor and PriorityOrdered. You know where to call this class.
Look directly at the postProcessBeanDefinitionRegistry method.
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); } // Avoid duplicate parsing this.registriesPostProcessed.add(registryId); processConfigBeanDefinitions(registry); }
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) { List<BeanDefinitionHolder> configCandidates = new ArrayList<>(); // Find all registered bean names String[] candidateNames = registry.getBeanDefinitionNames(); for (String beanName : candidateNames) { BeanDefinition beanDef = registry.getBeanDefinition(beanName); if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) { if (logger.isDebugEnabled()) { logger.debug("Bean definition has already been processed as a configuration class: " + beanDef); } } // If it is annotated with @ configuration annotation, add the collection 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 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 SingletonBeanRegistry sbr = null; if (registry instanceof SingletonBeanRegistry) { sbr = (SingletonBeanRegistry) registry; if (!this.localBeanNameGeneratorSet) { BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton( AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR); if (generator != null) { this.componentScanBeanNameGenerator = generator; this.importBeanNameGenerator = generator; } } } if (this.environment == null) { this.environment = new StandardEnvironment(); } // Create @ Configuration class parser ConfigurationClassParser parser = new ConfigurationClassParser( this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry); Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates); Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size()); do { // Resolve the current candidate configuration class. parser.parse(candidates); parser.validate(); // The rest of the code: first analyze parser parse(candidates); . . . . }
Skip some methods and look at this directly:
protected final void parse(@Nullable String className, String beanName) throws IOException { Assert.notNull(className, "No bean class name for configuration class bean definition"); MetadataReader reader = this.metadataReaderFactory.getMetadataReader(className); processConfigurationClass(new ConfigurationClass(reader, beanName)); }
Each configuration class corresponds to a ConfigurationClass;
Real parsing configuration class:
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // The configuration class must be marked with the Component annotation. // This method resolves the internal class. If the internal class is marked with @ configuration annotation, it will resolve the internal class first. if (configClass.getMetadata().isAnnotated(Component.class.getName())) { processMemberClasses(configClass, sourceClass); } // @The logic of PropertySource parsing this annotation is also very simple, that is, parse the property file and put the key value pair into the environment. for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable( sourceClass.getMetadata(), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { if (this.environment instanceof ConfigurableEnvironment) { processPropertySource(propertySource); } else { logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment"); } } // Parse @ ComponentScan annotation // According to the registration, scan the package, directly inject the bean and return the beanDefinition set. // Filter from. If it is a configuration class, the configuration class should also be resolved. 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 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) { BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition(); if (bdCand == null) { bdCand = holder.getBeanDefinition(); } // If the configuration class is scanned, enter the parsing logic. if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) { parse(bdCand.getBeanClassName(), holder.getBeanName()); } } } } // @Import import configuration class. The target is the import tag in xml. // getImports(sourceClass) is the class set by the import annotation. processImports(configClass, sourceClass, getImports(sourceClass), true); // Process any @ImportResource annotations AnnotationAttributes importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class); if (importResource != null) { String[] resources = importResource.getStringArray("locations"); Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader"); for (String resource : resources) { String resolvedResource = this.environment.resolveRequiredPlaceholders(resource); configClass.addImportedResource(resolvedResource, readerClass); } } // Parse @ Bean annotation: find all methods and add them to the configClass attribute. Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass); for (MethodMetadata methodMetadata : beanMethods) { configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass)); } // Process default methods on interfaces processInterfaces(configClass, sourceClass); // Process superclass, if any if (sourceClass.getMetadata().hasSuperClass()) { String superclass = sourceClass.getMetadata().getSuperClassName(); if (superclass != null && !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; }
Note that it is only resolved here and then added to the attribute of configClass. It is not encapsulated as bd
Resolve inner class
private void processMemberClasses(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { // Get the inner class collection Collection<SourceClass> memberClasses = sourceClass.getMemberClasses(); if (!memberClasses.isEmpty()) { List<SourceClass> candidates = new ArrayList<>(memberClasses.size()); for (SourceClass memberClass : memberClasses) { // If the inner class is annotated with the @ configuration annotation, it is added to the collection. if (ConfigurationClassUtils.isConfigurationCandidate(memberClass.getMetadata()) && !memberClass.getMetadata().getClassName().equals(configClass.getMetadata().getClassName())) { candidates.add(memberClass); } } OrderComparator.sort(candidates); // Traverse the collection. Resolve internal configuration class: for (SourceClass candidate : candidates) { if (this.importStack.contains(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { // What comes in here is the class of the inner class processConfigurationClass(candidate.asConfigClass(configClass)); } finally { this.importStack.pop(); } } } } }
Parse import annotation
The basis is as follows:
import is the imported configuration class;
If the class marked in the import annotation is of ImportSelector type, the selectImports method of this class returns the imported configuration class, not this class.
If the annotated class is ImportBeanDefinitionRegistrar, it will be passed into the registry. Register yourself.
If it is a normal type, then this class is the real configuration class.
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass, Collection<SourceClass> importCandidates, boolean checkForCircularImports) { // Collection < sourceclass > importcandidates is the class marked in the import annotation if (importCandidates.isEmpty()) { return; } if (checkForCircularImports && isChainedImportOnStack(configClass)) { this.problemReporter.error(new CircularImportProblem(configClass, this.importStack)); } else { this.importStack.push(configClass); try { // Traverse these classes. for (SourceClass candidate : importCandidates) { // If it is of ImportSelector type, if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class, this.environment, this.resourceLoader, this.registry); if (selector instanceof DeferredImportSelector) { this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector); } else { // See here? Get the return value of the selectImports method, call this method processImports again, and analyze it until you find the ordinary class or ImportBeanDefinitionRegistrar class. 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 -> // The of ImportBeanDefinitionRegistrar type will be instantiated and then added to the property of configClass. Class<?> candidateClass = candidate.loadClass(); ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class, this.environment, this.resourceLoader, this.registry); configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } else { // If it is an ordinary bean, it is a configuration class. Put it into the attribute of configClass and notify to resolve the configuration class again. Call the processConfigurationClass method. this.importStack.registerImport( currentSourceClass.getMetadata(), candidate.getMetadata().getClassName()); processConfigurationClass(candidate.asConfigClass(configClass)); } } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } finally { this.importStack.pop(); } } }
The import annotation is very complex and needs to be thought over:
It can be understood as follows: ImportSelector is the of classes imported in batch. ImportBeanDefinitionRegistrar adds beanDefinition manually, and ordinary is the real configuration class.
Sort out and analyze which block has generated a new ConfigurationClass.
- Inner class
- Package scanning. If it is a configuration class, a new one will be generated.
- import annotation, ordinary, will generate a new one.
Note that generating a new is to further parse the class. All configurationclasses are cached in ConfigurationClassParser.
Let's take a look at the remaining methods of processConfigBeanDefinitions:
do { parser.parse(candidates); parser.validate(); // Here you get all the configuration classes. 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()); } // Encapsulate the configuration class as bd 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<>(); for (ConfigurationClass configurationClass : alreadyParsed) { alreadyParsedClasses.add(configurationClass.getMetadata().getClassName()); } 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());
The reason for using the while loop. It is to judge whether a new configuration class is generated. If there is something, it needs to be parsed again.
Encapsulated as beanDefinition
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.removeImportingClass(configClass.getMetadata().getClassName()); return; } // It is a common class of import. // Several annotations are parsed: @ lazy, @ dependent, @ primary, etc if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } // Bean method is mainly used to encapsulate the attributes in @ bean annotation into the attributes in bd. // This method is set as factory method for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } // The configuration file is introduced, and the xmlBeanDefinitionreader parses the configuration file loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); //This is the importBeanDefinitionRegistrar type in import. Call method. Register manually. loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
At this point, the bean has been parsed..