spring source code - @ Configuration and @ ComponentScan parsing principle

Posted by flientje on Thu, 10 Mar 2022 17:14:06 +0100

I believe everyone is familiar with the core refresh method started by the spring container. The invokebeanfactoryprocessors method is a very important method for processing beanFactory, @ Component @Bean and so on.
1 @Configuration
2 @ComponentScan("org.springframework.context.annotation")
3 public class MyComponentScan {
4     @ComponentScan("org.springframework.context.annotation")
5     @Configuration
6     class InnerClass{
7     }
8 }
Next, take MyComponentScan as an example to debug and enter the invokebeanfactoryprocessors method.
 1 @Override
 2 public void refresh() throws BeansException, IllegalStateException {
 3    synchronized (this.startupShutdownMonitor) {
 4       // Prepare this context for refreshing.
 5       prepareRefresh();
 6 
 7       // Tell the subclass to refresh the internal bean factory.
 8       // To create a container object: DefaultListableBeanFactory
 9       // load xml The attribute value of the configuration file into the current factory, the most important is BeanDefinition
10       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
11 
12       // Prepare the bean factory for use in this context.
13       // beanFactory To fill in various attributes
14       prepareBeanFactory(beanFactory);
15 
16       try {
17          // Allows post-processing of the bean factory in context subclasses.
18          // Subclass override methods do additional processing. We generally do not do any extension work here, but you can view it web The code in has a specific implementation
19          postProcessBeanFactory(beanFactory);
20 
21          // Invoke factory processors registered as beans in the context.
22          // Call various beanFactory processor
23          invokeBeanFactoryPostProcessors(beanFactory);
24 
25          // Register bean processors that intercept bean creation.
26          // register bean Processor, here is only the registration function. What is really called is getBean method
27          registerBeanPostProcessors(beanFactory);
28 
29          // Initialize message source for this context.
30          // Initialize for context message Source, i.e. message bodies in different languages, international processing,stay springmvc Focus on international code
31          initMessageSource();
32 
33          // Initialize event multicaster for this context.
34          // Initialize event listening multiplexer
35          initApplicationEventMulticaster();
36 
37          // Initialize other special beans in specific context subclasses.
38          // Leave it to subclasses to initialize others bean
39          onRefresh();
40 
41          // Check for listener beans and register them.
42          // In all registered bean Find in listener bean,Register with message broadcaster
43          registerListeners();
44 
45          // Instantiate all remaining (non-lazy-init) singletons.
46          // Initialize the remaining single instance (non lazy loading)
47          finishBeanFactoryInitialization(beanFactory);
48 
49          // Last step: publish corresponding event.
50          // Complete the refresh process and notify the lifecycle processor lifecycleProcessor Refresh process, issued at the same time ContextRefreshEvent Inform others
51          finishRefresh();
52       }
53 
54       catch (BeansException ex) {
55          if (logger.isWarnEnabled()) {
56             logger.warn("Exception encountered during context initialization - " +
57                   "cancelling refresh attempt: " + ex);
58          }
59 
60          // Destroy already created singletons to avoid dangling resources.
61          // To prevent bean Resource occupation: in exception handling, destroy the single piece generated in the previous process bean
62          destroyBeans();
63 
64          // Reset 'active' flag.
65          // Reset active sign
66          cancelRefresh(ex);
67 
68          // Propagate exception to caller.
69          throw ex;
70       }
71 
72       finally {
73          // Reset common introspection caches in Spring's core, since we
74          // might not ever need metadata for singleton beans anymore...
75          resetCommonCaches();
76       }
77    }
78 }
In this method, we have to mention an interface - beanfactoryprocessor. As a post processor, beanfactoryprocessor is mainly used to process some information of BeanFactory. However, if there is only beanfactoryprocessor, it is necessary to define relevant operations on various objects in the beanfactoryprocessor method, BeanDefinition (a form of expression in which the objects defined in the configuration file are loaded into the spring container before instantiation) is the core and key point. Therefore, this thing is abstracted to a level and a subclass BeanDefinitionRegistryPostProcessor is made to add, delete, modify and query BeanDefinition. To resolve these annotations here, we need to use the implementation class ConfigurationClassPostProcessor class of BeanDefinitionRegistryPostProcessor class. As shown in the following code, in the beanfactoryprocessor traversing many loops, we focus on the processing link in line 64

  1 public static void invokeBeanFactoryPostProcessors(
  2             ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
  3 
  4         // Invoke BeanDefinitionRegistryPostProcessors first, if any.
  5         // In any case, priority should be given to implementation BeanDefinitionRegistryPostProcessors
  6         // Will have been executed BFPP store in processedBeans To prevent repeated execution
  7         Set<String> processedBeans = new HashSet<>();
  8 
  9         // judge beanfactory Is it BeanDefinitionRegistry Type, here is DefaultListableBeanFactory,Realized BeanDefinitionRegistry Interface, so true
 10         if (beanFactory instanceof BeanDefinitionRegistry) {
 11             // Type conversion
 12             BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
 13             // I hope you can make a distinction here. The two interfaces are different, BeanDefinitionRegistryPostProcessor yes BeanFactoryPostProcessor Subset of
 14             // BeanFactoryPostProcessor The main operation objects are BeanFactory,and BeanDefinitionRegistryPostProcessor The main operation objects are BeanDefinition
 15             // deposit BeanFactoryPostProcessor Collection of
 16             List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
 17             // deposit BeanDefinitionRegistryPostProcessor Collection of
 18             List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
 19 
 20             // First process the input in the parameter beanFactoryPostProcessors,Traverse all beanFactoryPostProcessors,take BeanDefinitionRegistryPostProcessor
 21             // and BeanFactoryPostProcessor Distinguish
 22             for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
 23                 // If it is BeanDefinitionRegistryPostProcessor
 24                 if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
 25                     BeanDefinitionRegistryPostProcessor registryProcessor =
 26                             (BeanDefinitionRegistryPostProcessor) postProcessor;
 27                     // Direct execution BeanDefinitionRegistryPostProcessor In the interface postProcessBeanDefinitionRegistry method
 28                     registryProcessor.postProcessBeanDefinitionRegistry(registry);
 29                     // Add to registryProcessors,For subsequent execution postProcessBeanFactory method
 30                     registryProcessors.add(registryProcessor);
 31                 } else {
 32                     // Otherwise, it's just ordinary BeanFactoryPostProcessor,Add to regularPostProcessors,For subsequent execution postProcessBeanFactory method
 33                     regularPostProcessors.add(postProcessor);
 34                 }
 35             }
 36 
 37             // Do not initialize FactoryBeans here: We need to leave all regular beans
 38             // uninitialized to let the bean factory post-processors apply to them!
 39             // Separate between BeanDefinitionRegistryPostProcessors that implement
 40             // PriorityOrdered, Ordered, and the rest.
 41             // Used to save the current execution BeanDefinitionRegistryPostProcessor
 42             List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
 43 
 44             // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
 45             // Call all implementations PriorityOrdered Interfaced BeanDefinitionRegistryPostProcessor Implementation class
 46             // Find all implementations BeanDefinitionRegistryPostProcessor Interface bean of beanName
 47             String[] postProcessorNames =
 48                     beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
 49             // Traverse and process all that meet the rules postProcessorNames
 50             for (String ppName : postProcessorNames) {
 51                 // Check whether it is implemented PriorityOrdered Interface
 52                 if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
 53                     // Get the corresponding name bean Instance, add to currentRegistryProcessors in
 54                     currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
 55                     // To be executed BFPP Add name to processedBeans,Avoid subsequent repeated execution
 56                     processedBeans.add(ppName);
 57                 }
 58             }
 59             // Sort operations by priority
 60             sortPostProcessors(currentRegistryProcessors, beanFactory);
 61             // Add to registryProcessors For final execution postProcessBeanFactory method
 62             registryProcessors.addAll(currentRegistryProcessors);
 63             // ergodic currentRegistryProcessors,implement postProcessBeanDefinitionRegistry method
 64             invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
 65             // After execution, empty currentRegistryProcessors
 66             currentRegistryProcessors.clear();
 67 
 68             // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
 69             // Call all implementations Ordered Interfaced BeanDefinitionRegistryPostProcessor Implementation class
 70             // Find all implementations BeanDefinitionRegistryPostProcessor Interface bean of beanName,
 71             // The reason why you need to search repeatedly here is that other information may be added during the above implementation process BeanDefinitionRegistryPostProcessor
 72             postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
 73             for (String ppName : postProcessorNames) {
 74                 // Check whether it is implemented Ordered Interface and has not been executed
 75                 if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
 76                     // Get the corresponding name bean Instance, adding to currentRegistryProcessors in
 77                     currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
 78                     // To be executed BFPP Add name to processedBeans,Avoid subsequent repeated execution
 79                     processedBeans.add(ppName);
 80                 }
 81             }
 82             // Sort operations by priority
 83             sortPostProcessors(currentRegistryProcessors, beanFactory);
 84             // Add to registryProcessors For final execution postProcessBeanFactory method
 85             registryProcessors.addAll(currentRegistryProcessors);
 86             // ergodic currentRegistryProcessors,implement postProcessBeanDefinitionRegistry method
 87             invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
 88             // After execution, empty currentRegistryProcessors
 89             currentRegistryProcessors.clear();
 90 
 91             // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
 92             // Finally, call all the rest. BeanDefinitionRegistryPostProcessors
 93             boolean reiterate = true;
 94             while (reiterate) {
 95                 reiterate = false;
 96                 // Find all implementations BeanDefinitionRegistryPostProcessor Class of interface
 97                 postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
 98                 // Traversal execution
 99                 for (String ppName : postProcessorNames) {
100                     // Skip already executed BeanDefinitionRegistryPostProcessor
101                     if (!processedBeans.contains(ppName)) {
102                         // Get the corresponding name bean Instance, adding to currentRegistryProcessors in
103                         currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
104                         // To be executed BFPP Add name to processedBeans,Avoid subsequent repeated execution
105                         processedBeans.add(ppName);
106                         reiterate = true;
107                     }
108                 }
109                 // Sort operations by priority
110                 sortPostProcessors(currentRegistryProcessors, beanFactory);
111                 // Add to registryProcessors For final execution postProcessBeanFactory method
112                 registryProcessors.addAll(currentRegistryProcessors);
113                 // ergodic currentRegistryProcessors,implement postProcessBeanDefinitionRegistry method
114                 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
115                 // After execution, empty currentRegistryProcessors
116                 currentRegistryProcessors.clear();
117             }
118 
119             // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
120             // Call all BeanDefinitionRegistryPostProcessor of postProcessBeanFactory method
121             invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
122             // Finally, call in parameter. beanFactoryPostProcessors Common in BeanFactoryPostProcessor of postProcessBeanFactory method
123             invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
124         } else {
125             // Invoke factory processors registered with the context instance.
126             // If beanFactory Not attributable to BeanDefinitionRegistry Type, then execute directly postProcessBeanFactory method
127             invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
128         }
129 
130         // So far, enter the reference beanFactoryPostProcessors And all in the container BeanDefinitionRegistryPostProcessor All processing has been completed. Now start processing in the container
131         // be-all BeanFactoryPostProcessor
132         // It may contain some implementation classes, which only implement BeanFactoryPostProcessor,Not implemented BeanDefinitionRegistryPostProcessor Interface
133 
134         // Do not initialize FactoryBeans here: We need to leave all regular beans
135         // uninitialized to let the bean factory post-processors apply to them!
136         // Find all implementations BeanFactoryPostProcessor Class of interface
137         String[] postProcessorNames =
138                 beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
139 
140         // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
141         // Ordered, and the rest.
142         // Used to store PriorityOrdered Interfaced BeanFactoryPostProcessor
143         List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
144         // Used to store Ordered Interfaced BeanFactoryPostProcessor of beanName
145 //    List<String> orderedPostProcessorNames = new ArrayList<>();
146         List<BeanFactoryPostProcessor> orderedPostProcessor = new ArrayList<>();
147         // For storing ordinary BeanFactoryPostProcessor of beanName
148 //    List<String> nonOrderedPostProcessorNames = new ArrayList<>();
149         List<BeanFactoryPostProcessor> nonOrderedPostProcessorNames = new ArrayList<>();
150         // ergodic postProcessorNames,take BeanFactoryPostProcessor By implementation PriorityOrdered,realization Ordered Interface and common are distinguished
151         for (String ppName : postProcessorNames) {
152             // Skip already executed BeanFactoryPostProcessor
153             if (processedBeans.contains(ppName)) {
154                 // skip - already processed in first phase above
155             }
156             // Added implementation PriorityOrdered Interfaced BeanFactoryPostProcessor reach priorityOrderedPostProcessors
157             else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
158                 priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
159             }
160             // Added implementation Ordered Interfaced BeanFactoryPostProcessor of beanName reach orderedPostProcessorNames
161             else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
162 //          orderedPostProcessorNames.add(ppName);
163                 orderedPostProcessor.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
164             } else {
165                 // Add the remaining normal BeanFactoryPostProcessor of beanName reach nonOrderedPostProcessorNames
166 //          nonOrderedPostProcessorNames.add(ppName);
167                 nonOrderedPostProcessorNames.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
168             }
169         }
170 
171         // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
172         // Yes, it is PriorityOrdered Interfaced BeanFactoryPostProcessor Sort
173         sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
174         // Traversal implementation PriorityOrdered Interfaced BeanFactoryPostProcessor,implement postProcessBeanFactory method
175         invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
176 
177         // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
178         // Create and store Ordered Interfaced BeanFactoryPostProcessor aggregate
179 //    List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
180         // Traversal storage is realized Ordered Interfaced BeanFactoryPostProcessor Collection of names
181 //    for (String postProcessorName : orderedPostProcessorNames) {
182         // Will be achieved Ordered Interfaced BeanFactoryPostProcessor Add to collection
183 //       orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
184 //    }
185         // Yes, it is Ordered Interfaced BeanFactoryPostProcessor Sort operation
186 //    sortPostProcessors(orderedPostProcessors, beanFactory);
187         sortPostProcessors(orderedPostProcessor, beanFactory);
188         // Traversal implementation Ordered Interfaced BeanFactoryPostProcessor,implement postProcessBeanFactory method
189 //    invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
190         invokeBeanFactoryPostProcessors(orderedPostProcessor, beanFactory);
191 
192         // Finally, invoke all other BeanFactoryPostProcessors.
193         // Finally, create a common BeanFactoryPostProcessor Collection of
194 //    List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
195         // Traversal storage realizes common BeanFactoryPostProcessor Collection of names
196 //    for (String postProcessorName : nonOrderedPostProcessorNames) {
197         // Ordinary BeanFactoryPostProcessor Add to collection
198 //       nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
199 //    }
200         // Traversal ordinary BeanFactoryPostProcessor,implement postProcessBeanFactory method
201 //    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
202         invokeBeanFactoryPostProcessors(nonOrderedPostProcessorNames, beanFactory);
203 
204         // Clear cached merged bean definitions since the post-processors might have
205         // modified the original metadata, e.g. replacing placeholders in values...
206         // Clear metadata cache( mergeBeanDefinitions,allBeanNamesByType,singletonBeanNameByType)
207         // Because the post processor may have modified the original metadata, for example, the placeholder in the replacement value
208         beanFactory.clearMetadataCache();
209     }
Enter the processing link on line 12
 1 /**
 2  * Call the given BeanDefinitionRegistryPostProcessor Bean object
 3  *
 4  * Invoke the given BeanDefinitionRegistryPostProcessor beans.
 5  */
 6 private static void invokeBeanDefinitionRegistryPostProcessors(
 7         Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
 8 
 9     //ergodic postProcessors
10     for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
11         //call postProcessor of postProcessBeanDefinitionRegistry So that postProcess to registry register BeanDefinition object
12         postProcessor.postProcessBeanDefinitionRegistry(registry);
13     }
14 }
Enter the processing link on line 22
 1 /**
 2  * Locate, load, parse and register relevant annotations
 3  *
 4  * Derive further bean definitions from the configuration classes in the registry.
 5  */
 6 @Override
 7 public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
 8    // According to the corresponding registry Object generation hashcode Value, this object will operate only once. If it has been handled before, an exception will be thrown
 9    int registryId = System.identityHashCode(registry);
10    if (this.registriesPostProcessed.contains(registryId)) {
11       throw new IllegalStateException(
12             "postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
13    }
14    if (this.factoriesPostProcessed.contains(registryId)) {
15       throw new IllegalStateException(
16             "postProcessBeanFactory already called on this post-processor against " + registry);
17    }
18    // To be processed soon registry Object id Value into the collection object that has been processed
19    this.registriesPostProcessed.add(registryId);
20 
21    // Handling configuration classes bean Definition information
22    processConfigBeanDefinitions(registry);
23 }
The following methods are the core processing steps. BeanDefinitionHolder is the packaging class of BeanDefinition, including BeanDefinition, beanName and alias. After the configuration file is loaded, everything will be put into BeanDefinitionMap and BeanDefinitionNames, which is the name collection, The BeanDefinitionMap is the collection of KV key value pairs of name and complete BeanDefinition objects. Here, all the name collections are taken out.
The loop does only one thing, filtering out the BeanDefinition modified by some annotations.
Obtain the BeanDefinition and judge whether the BeanDefinition contains CONFIGURATION_CLASS_ATTRIBUTE attribute value (), excluding 126 lines of tool class.
  1 /**
  2  * Build and verify whether a class is modified by @ Configuration, and do relevant parsing work
  3  *
  4  * If you understand this method clearly, then the automatic assembly principle of springboot is clear
  5  *
  6  * Build and validate a configuration model based on the registry of
  7  * {@link Configuration} classes.
  8  */
  9 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 10    // Create storage BeanDefinitionHolder Collection of objects
 11    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
 12    // current registry namely DefaultListableBeanFactory,Get all registered BeanDefinition of beanName
 13    String[] candidateNames = registry.getBeanDefinitionNames();
 14 
 15    // Traverse all to be processed beanDefinition Name of,Filter corresponding beanDefinition(Annotated)
 16    for (String beanName : candidateNames) {
 17       // Gets the of the specified name BeanDefinition object
 18       BeanDefinition beanDef = registry.getBeanDefinition(beanName);
 19       // If beanDefinition Medium configurationClass If the attribute is not empty, it means that it has been processed and the log information is output
 20       if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
 21          if (logger.isDebugEnabled()) {
 22             logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
 23          }
 24       }
 25       // Judge the current BeanDefinition Whether it is a configuration class, and BeanDefinition Set property to lite perhaps full,The property value is set here for subsequent calls
 26       // If Configuration to configure proxyBeanMethods Agent for true Then full
 27       // If you add@Bean,@Component,@ComponentScan,@Import,@ImportResource Annotation, set to lite
 28       // If the configuration class is@Order Annotation, set BeanDefinition of order Attribute value
 29       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
 30          // Add to the corresponding collection object
 31          configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
 32       }
 33    }
 34 
 35    // Return immediately if no @Configuration classes were found
 36    // If no configuration class is found, return directly
 37    if (configCandidates.isEmpty()) {
 38       return;
 39    }
 40 
 41    // Sort by previously determined @Order value, if applicable
 42    // If applicable, according to the previously determined@Order Value sorting of
 43    configCandidates.sort((bd1, bd2) -> {
 44       int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
 45       int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
 46       return Integer.compare(i1, i2);
 47    });
 48 
 49    // Detect any custom bean name generation strategy supplied through the enclosing application context
 50    // Judge whether the current type is SingletonBeanRegistry type
 51    SingletonBeanRegistry sbr = null;
 52    if (registry instanceof SingletonBeanRegistry) {
 53       // Cast of type
 54       sbr = (SingletonBeanRegistry) registry;
 55       // Determine whether there is a custom beanName generator 
 56       if (!this.localBeanNameGeneratorSet) {
 57          // Get custom beanName generator 
 58          BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
 59                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
 60          // If there is a custom naming generation policy
 61             if (generator != null) {
 62             //Set the of component scanning beanName Generation strategy
 63             this.componentScanBeanNameGenerator = generator;
 64             // set up import bean name Generation strategy
 65             this.importBeanNameGenerator = generator;
 66          }
 67       }
 68    }
 69 
 70    // If the environment object is equal to null, the new environment object is recreated
 71    if (this.environment == null) {
 72       this.environment = new StandardEnvironment();
 73    }
 74 
 75    // Parse each @Configuration class
 76    // instantiation  ConfigurationClassParser Class, and initialize the relevant parameters to complete the parsing of the configuration class
 77    ConfigurationClassParser parser = new ConfigurationClassParser(
 78          this.metadataReaderFactory, this.problemReporter, this.environment,
 79          this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 80 
 81    // Create two collection objects,
 82    // Store relevant BeanDefinitionHolder object
 83    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 84    // Store all under the scanning package bean
 85    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 86    do {
 87       // Analytical band@Controller,@Import,@ImportResource,@ComponentScan,@ComponentScans,@Bean of BeanDefinition
 88       parser.parse(candidates);
 89       // To be parsed Configuration Check the configuration class. 1. The configuration class cannot be empty final,2,@Bean Decorated methods must be rewritable to support CGLIB
 90       parser.validate();
 91 
 92       // Get all bean,Include scanned bean Object,@Import Imported bean object
 93       Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 94       // Clear the configuration classes that have been resolved and processed
 95       configClasses.removeAll(alreadyParsed);
 96 
 97       // Read the model and create bean definitions based on its content
 98       // Judge whether the reader is empty. If it is empty, create a fully filled one ConfigurationClass Instance reader
 99       if (this.reader == null) {
100          this.reader = new ConfigurationClassBeanDefinitionReader(
101                registry, this.sourceExtractor, this.resourceLoader, this.environment,
102                this.importBeanNameGenerator, parser.getImportRegistry());
103       }
104       // The core method will be completely filled ConfigurationClass Convert instance to BeanDefinition Register in IOC container
105       this.reader.loadBeanDefinitions(configClasses);
106       // Add to the processed collection
107       alreadyParsed.addAll(configClasses);
108 
109       candidates.clear();
110       // Judge here registry.getBeanDefinitionCount() > candidateNames.length The purpose is to know reader.loadBeanDefinitions(configClasses)Is there any direction in this step BeanDefinitionMap Add new to BeanDefinition
111       // In fact, it depends on the configuration class(for example AppConfig Class will BeanDefinitionMap Add in bean)
112       // If so, registry.getBeanDefinitionCount()Will be greater than candidateNames.length
113       // In this way, you need to traverse the newly added BeanDefinition,And judge these bean Has it been parsed? If not, it needs to be parsed again
114       // there AppConfig Class added to the container bean,Actually parser.parse()This step has been fully resolved
115       if (registry.getBeanDefinitionCount() > candidateNames.length) {
116          String[] newCandidateNames = registry.getBeanDefinitionNames();
117          Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
118          Set<String> alreadyParsedClasses = new HashSet<>();
119          for (ConfigurationClass configurationClass : alreadyParsed) {
120             alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
121          }
122          // If there are unresolved classes, add them to candidates In this way candidates If it is not empty, it will enter the next time while In the cycle of
123          for (String candidateName : newCandidateNames) {
124             if (!oldCandidateNames.contains(candidateName)) {
125                BeanDefinition bd = registry.getBeanDefinition(candidateName);
126                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
127                      !alreadyParsedClasses.contains(bd.getBeanClassName())) {
128                   candidates.add(new BeanDefinitionHolder(bd, candidateName));
129                }
130             }
131          }
132          candidateNames = newCandidateNames;
133       }
134    }
135    while (!candidates.isEmpty());
136 
137    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
138    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
139       sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
140    }
141 
142    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
143       // Clear cache in externally provided MetadataReaderFactory; this is a no-op
144       // for a shared cache since it'll be cleared by the ApplicationContext.
145       ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
146    }
147 }
It should be noted that if the BeanDefinition is read directly from the configuration file, the implementation class is GenericBeanDefinition. If the annotation method is adopted, the implementation class is ScannedGenericBeanDefinition, and the AnnotatedBeanDefinition interface is implemented, in fact, there is a special processing of metadata information related to annotation.
 1 public interface AnnotatedBeanDefinition extends BeanDefinition {
 2    /**
 3     * Get metadata of annotation
 4     *
 5     * Obtain the annotation metadata (as well as basic class metadata)
 6     * for this bean definition's bean class.
 7     * @return the annotation metadata object (never {@code null})
 8     */
 9    AnnotationMetadata getMetadata();
10    /**
11     * Get metadata of factory method
12     *
13     * Obtain metadata for this bean definition's factory method, if any.
14     * @return the factory method metadata, or {@code null} if none
15     * @since 4.1.1
16     */
17    @Nullable
18    MethodMetadata getFactoryMethodMetadata();
19 }
Line 26. No matter whether the three methods match any one, the ultimate goal is to obtain the AnnotatedMetadata object. Only after obtaining the annotation metadata information can we know what annotation the current BeanDefinition has. The following 66 lines first judge whether it is a Configuration class. Go down to isConfigurationCandidate to judge whether it contains other annotations. Go in 72 lines.
 1 /**
 2  * Check whether the currently given beanDefinition is a candidate for a configuration class,
 3  * Judge whether the nested relationship contains configuration classes or component classes or automatically registered ones, and mark them accordingly
 4  *
 5  * Check whether the given bean definition is a candidate for a configuration class
 6  * (or a nested component class declared within a configuration/component class,
 7  * to be auto-registered as well), and mark it accordingly.
 8  * @param beanDef the bean definition to check
 9  * @param metadataReaderFactory the current factory in use by the caller
10  * @return whether the candidate qualifies as (any kind of) configuration class
11  */
12 public static boolean checkConfigurationClassCandidate(
13       BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
14 
15    // obtain bean Definition information class Class name
16    String className = beanDef.getBeanClassName();
17    // If className Empty, or bean Definition information factoryMethod Not equal to null, then return directly
18    if (className == null || beanDef.getFactoryMethodName() != null) {
19       return false;
20    }
21 
22    AnnotationMetadata metadata;
23    // Injected by annotation db All AnnotatedGenericBeanDefinition,Realized AnnotatedBeanDefinition
24    // spring Internal bd yes RootBeanDefinition,Realized AbstractBeanDefinition
25    // This is mainly used to judge whether it belongs to AnnotatedBeanDefinition
26    if (beanDef instanceof AnnotatedBeanDefinition &&
27          className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
28       // Can reuse the pre-parsed metadata from the given BeanDefinition...
29       // From current bean Get metadata information from the definition information of
30       metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
31    }
32    // Judge whether it is spring Default in BeanDefinition
33    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
34       // Check already loaded Class if present...
35       // since we possibly can't even load the class file for this Class.
36       // Get current bean Object Class object
37       Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
38       // If class Instances are any of the following four types or subclasses and parent interfaces of interfaces, which are returned directly
39       if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
40             BeanPostProcessor.class.isAssignableFrom(beanClass) ||
41             AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
42             EventListenerFactory.class.isAssignableFrom(beanClass)) {
43          return false;
44       }
45       // Create a new for the given class AnnotationMetadata example
46       metadata = AnnotationMetadata.introspect(beanClass);
47    }
48    // If neither of the above conditions is met
49    else {
50       try {
51          // obtain className of MetadataReader example
52          MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
53          // Read the complete annotated metadata of the underlying class, including the metadata of annotated methods
54          metadata = metadataReader.getAnnotationMetadata();
55       }
56       catch (IOException ex) {
57          if (logger.isDebugEnabled()) {
58             logger.debug("Could not find class file for introspecting configuration annotations: " +
59                   className, ex);
60          }
61          return false;
62       }
63    }
64 
65    // obtain bean Defined metadata is@Configuration Attribute dictionary value of annotation annotation
66    Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
67    // If bean cover@Configuration Annotation and attribute proxyBeanMethods by false(Use proxy mode),Will bean The definition is recorded as full
68    if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
69       beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
70    }
71    // If bean cover@configuration Annotated and annotated@Component,@ComponentScan,@Import,@ImportResource perhaps@Bean Marked method, the bean Define tag as lite
72    else if (config != null || isConfigurationCandidate(metadata)) {
73       beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
74    }
75    else {
76       return false;
77    }
78 
79    // It's a full or lite configuration candidate... Let's determine the order value, if any.
80    // bean Definition is a tag full or lite Candidates for, if set order Then set order Attribute value
81    Integer order = getOrder(metadata);
82    // If the value is not empty, set the value directly to the specific value beanDefinition
83    if (order != null) {
84       // set up bean Defined order value
85       beanDef.setAttribute(ORDER_ATTRIBUTE, order);
86    }
87 
88    return true;
89 }
The method iterates through the set in 19 lines. Four annotations are defined in the set: Component, ComponentScan, Import and ImportResource. If there is no match, check whether the method with @ Bean annotation is included
 1 /**
 2  * Check the given metadata to find out whether the given candidate configuration class is annotated by the specified annotation
 3  *
 4  * Check the given metadata for a configuration class candidate
 5  * (or nested component class declared within a configuration/component class).
 6  * @param metadata the metadata of the annotated class
 7  * @return {@code true} if the given class is to be registered for
 8  * configuration class processing; {@code false} otherwise
 9  */
10 public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
11    // Do not consider an interface or an annotation...
12    // Interfaces or annotations are not considered
13    if (metadata.isInterface()) {
14       return false;
15    }
16 
17    // Any of the typical annotations found?
18    // Check whether it is annotated@Component,@ComponentScan,@Import,@ImportResource tagging
19    for (String indicator : candidateIndicators) {
20       if (metadata.isAnnotated(indicator)) {
21          return true;
22       }
23    }
24 
25    // Finally, let's look for @Bean methods...
26    // Finally, check whether there is@Bean Annotation method
27    try {
28       return metadata.hasAnnotatedMethods(Bean.class.getName());
29    }
30    catch (Throwable ex) {
31       if (logger.isDebugEnabled()) {
32          logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
33       }
34       return false;
35    }
36 }
Our MyComponentScan contains @ Component, so line 73 is added. Set the attribute value key to configurationClass in the current BeanDefinition. The attribute value is the LinkedHashMap structure. The value of the attribute value is full or lite. The current annotation is marked with @ Configuration as full, and the Configuration class not marked with @ Configuration as Lite. Finally, return true

 1 /**
 2  * Check whether the currently given beanDefinition is a candidate for a configuration class,
 3  * Judge whether the nested relationship contains configuration classes or component classes or automatically registered ones, and mark them accordingly
 4  *
 5  * Check whether the given bean definition is a candidate for a configuration class
 6  * (or a nested component class declared within a configuration/component class,
 7  * to be auto-registered as well), and mark it accordingly.
 8  * @param beanDef the bean definition to check
 9  * @param metadataReaderFactory the current factory in use by the caller
10  * @return whether the candidate qualifies as (any kind of) configuration class
11  */
12 public static boolean checkConfigurationClassCandidate(
13       BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
14 
15    // obtain bean Definition information class Class name
16    String className = beanDef.getBeanClassName();
17    // If className Or, null bean Definition information factoryMethod Not equal to null, then return directly
18    if (className == null || beanDef.getFactoryMethodName() != null) {
19       return false;
20    }
21 
22    AnnotationMetadata metadata;
23    // Injected by annotation db All AnnotatedGenericBeanDefinition,Realized AnnotatedBeanDefinition
24    // spring Internal bd yes RootBeanDefinition,Realized AbstractBeanDefinition
25    // This is mainly used to judge whether it belongs to AnnotatedBeanDefinition
26    if (beanDef instanceof AnnotatedBeanDefinition &&
27          className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
28       // Can reuse the pre-parsed metadata from the given BeanDefinition...
29       // From current bean Get metadata information from the definition information of
30       metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
31    }
32    // Judge whether it is spring Default in BeanDefinition
33    else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
34       // Check already loaded Class if present...
35       // since we possibly can't even load the class file for this Class.
36       // Get current bean Object Class object
37       Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
38       // If class Instances are any of the following four types or subclasses and parent interfaces of interfaces, which are returned directly
39       if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
40             BeanPostProcessor.class.isAssignableFrom(beanClass) ||
41             AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
42             EventListenerFactory.class.isAssignableFrom(beanClass)) {
43          return false;
44       }
45       // Create a new for the given class AnnotationMetadata example
46       metadata = AnnotationMetadata.introspect(beanClass);
47    }
48    // If neither of the above conditions is met
49    else {
50       try {
51          // obtain className of MetadataReader example
52          MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
53          // Read the complete annotated metadata of the underlying class, including the metadata of annotated methods
54          metadata = metadataReader.getAnnotationMetadata();
55       }
56       catch (IOException ex) {
57          if (logger.isDebugEnabled()) {
58             logger.debug("Could not find class file for introspecting configuration annotations: " +
59                   className, ex);
60          }
61          return false;
62       }
63    }
64 
65    // obtain bean Defined metadata is@Configuration Attribute dictionary value of annotation annotation
66    Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
67    // If bean cover@Configuration Annotation and attribute proxyBeanMethods by false(Use proxy mode),Will bean The definition is recorded as full
68    if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
69       beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
70    }
71    // If bean cover@configuration Annotated and annotated@Component,@ComponentScan,@Import,@ImportResource perhaps@Bean Marked method, the bean Define tag as lite
72    else if (config != null || isConfigurationCandidate(metadata)) {
73       beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
74    }
75    else {
76       return false;
77    }
78 
79    // It's a full or lite configuration candidate... Let's determine the order value, if any.
80    // bean Definition is a tag full or lite Candidates for, if set order Then set order Attribute value
81    Integer order = getOrder(metadata);
82    // If the value is not empty, set the value directly to the specific value beanDefinition
83    if (order != null) {
84       // set up bean Defined order value
85       beanDef.setAttribute(ORDER_ATTRIBUTE, order);
86    }
87 
88    return true;
89 }
In line 31, the current BeanDefinition is encapsulated into a BeanDefinitionHolder object and added to the configCandidates collection, indicating that it is a configuration class, which will be parsed later.
Sort according to order to determine whether there is a custom beanName generator in the current configuration. If so, load it.
Create a parser object of configuration class in advance, prepare the collection of holder objects and the processed collection in advance.
Line 88, start processing the entire parsing.
  1 /**
  2  * Build and verify whether a class is modified by @ Configuration, and do relevant parsing work
  3  *
  4  * If you understand this method clearly, then the automatic assembly principle of springboot is clear
  5  *
  6  * Build and validate a configuration model based on the registry of
  7  * {@link Configuration} classes.
  8  */
  9 public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
 10    // Create storage BeanDefinitionHolder Collection of objects
 11    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
 12    // current registry namely DefaultListableBeanFactory,Get all registered BeanDefinition of beanName
 13    String[] candidateNames = registry.getBeanDefinitionNames();
 14 
 15    // Traverse all to be processed beanDefinition Name of,Filter corresponding beanDefinition(Annotated)
 16    for (String beanName : candidateNames) {
 17       // Gets the of the specified name BeanDefinition object
 18       BeanDefinition beanDef = registry.getBeanDefinition(beanName);
 19       // If beanDefinition Medium configurationClass If the attribute is not empty, it means that it has been processed and the log information is output
 20       if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
 21          if (logger.isDebugEnabled()) {
 22             logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
 23          }
 24       }
 25       // Judge the current BeanDefinition Whether it is a configuration class, and BeanDefinition Set property to lite perhaps full,The property value is set here for subsequent calls
 26       // If Configuration to configure proxyBeanMethods Agent for true Then full
 27       // If you add@Bean,@Component,@ComponentScan,@Import,@ImportResource Annotation, set to lite
 28       // If the configuration class is@Order Annotation, set BeanDefinition of order Attribute value
 29       else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
 30          // Add to the corresponding collection object
 31          configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
 32       }
 33    }
 34 
 35    // Return immediately if no @Configuration classes were found
 36    // If no configuration class is found, return directly
 37    if (configCandidates.isEmpty()) {
 38       return;
 39    }
 40 
 41    // Sort by previously determined @Order value, if applicable
 42    // If applicable, according to the previously determined@Order Value sorting of
 43    configCandidates.sort((bd1, bd2) -> {
 44       int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
 45       int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
 46       return Integer.compare(i1, i2);
 47    });
 48 
 49    // Detect any custom bean name generation strategy supplied through the enclosing application context
 50    // Judge whether the current type is SingletonBeanRegistry type
 51    SingletonBeanRegistry sbr = null;
 52    if (registry instanceof SingletonBeanRegistry) {
 53       // Cast of type
 54       sbr = (SingletonBeanRegistry) registry;
 55       // Determine whether there is a custom beanName generator 
 56       if (!this.localBeanNameGeneratorSet) {
 57          // Get custom beanName generator 
 58          BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
 59                AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
 60          // If there is a custom naming generation policy
 61             if (generator != null) {
 62             //Set the of component scanning beanName Generation strategy
 63             this.componentScanBeanNameGenerator = generator;
 64             // set up import bean name Generation strategy
 65             this.importBeanNameGenerator = generator;
 66          }
 67       }
 68    }
 69 
 70    // If the environment object is equal to null, the new environment object is recreated
 71    if (this.environment == null) {
 72       this.environment = new StandardEnvironment();
 73    }
 74 
 75    // Parse each @Configuration class
 76    // instantiation  ConfigurationClassParser Class, and initialize the relevant parameters to complete the parsing of the configuration class
 77    ConfigurationClassParser parser = new ConfigurationClassParser(
 78          this.metadataReaderFactory, this.problemReporter, this.environment,
 79          this.resourceLoader, this.componentScanBeanNameGenerator, registry);
 80 
 81    // Create two collection objects,
 82    // Store relevant BeanDefinitionHolder object
 83    Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
 84    // Store all under the scanning package bean
 85    Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
 86    do {
 87       // Analytical band@Controller,@Import,@ImportResource,@ComponentScan,@ComponentScans,@Bean of BeanDefinition
 88       parser.parse(candidates);
 89       // To be parsed Configuration Check the configuration class. 1. The configuration class cannot be empty final,2,@Bean Decorated methods must be rewritable to support CGLIB
 90       parser.validate();
 91 
 92       // Get all bean,Include scanned bean Object,@Import Imported bean object
 93       Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
 94       // Clear the configuration classes that have been resolved and processed
 95       configClasses.removeAll(alreadyParsed);
 96 
 97       // Read the model and create bean definitions based on its content
 98       // Judge whether the reader is empty. If it is empty, create a fully filled one ConfigurationClass Instance reader
 99       if (this.reader == null) {
100          this.reader = new ConfigurationClassBeanDefinitionReader(
101                registry, this.sourceExtractor, this.resourceLoader, this.environment,
102                this.importBeanNameGenerator, parser.getImportRegistry());
103       }
104       // The core method will be completely filled ConfigurationClass Convert instance to BeanDefinition Register in IOC container
105       this.reader.loadBeanDefinitions(configClasses);
106       // Add to the processed collection
107       alreadyParsed.addAll(configClasses);
108 
109       candidates.clear();
110       // Judge here registry.getBeanDefinitionCount() > candidateNames.length The purpose is to know reader.loadBeanDefinitions(configClasses)Is there any direction in this step BeanDefinitionMap Add new to BeanDefinition
111       // In fact, it depends on the configuration class(for example AppConfig Class will BeanDefinitionMap Add in bean)
112       // If so, registry.getBeanDefinitionCount()Will be greater than candidateNames.length
113       // In this way, you need to traverse the newly added BeanDefinition,And judge these bean Has it been parsed? If not, it needs to be parsed again
114       // there AppConfig Class added to the container bean,Actually parser.parse()This step has been fully resolved
115       if (registry.getBeanDefinitionCount() > candidateNames.length) {
116          String[] newCandidateNames = registry.getBeanDefinitionNames();
117          Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
118          Set<String> alreadyParsedClasses = new HashSet<>();
119          for (ConfigurationClass configurationClass : alreadyParsed) {
120             alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
121          }
122          // If there are unresolved classes, add them to candidates In this way candidates If it is not empty, it will enter the next time while In the cycle of
123          for (String candidateName : newCandidateNames) {
124             if (!oldCandidateNames.contains(candidateName)) {
125                BeanDefinition bd = registry.getBeanDefinition(candidateName);
126                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
127                      !alreadyParsedClasses.contains(bd.getBeanClassName())) {
128                   candidates.add(new BeanDefinitionHolder(bd, candidateName));
129                }
130             }
131          }
132          candidateNames = newCandidateNames;
133       }
134    }
135    while (!candidates.isEmpty());
136 
137    // Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
138    if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
139       sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
140    }
141 
142    if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
143       // Clear cache in externally provided MetadataReaderFactory; this is a no-op
144       // for a shared cache since it'll be cleared by the ApplicationContext.
145       ((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
146    }
147 }
The input parameter is a collection. The parsing needs to make a circular judgment, obtain the current BeanDefinition, and judge which type the BeanDefinition belongs to.
 1 public void parse(Set<BeanDefinitionHolder> configCandidates) {
 2    // Loop traversal configCandidates
 3    for (BeanDefinitionHolder holder : configCandidates) {
 4       // obtain BeanDefinition
 5       BeanDefinition bd = holder.getBeanDefinition();
 6       // according to BeanDefinition Different types, call parse Different overloaded methods are actually called in the end processConfigurationClass()method
 7       try {
 8          // annotation type 
 9          if (bd instanceof AnnotatedBeanDefinition) {
10             parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
11          }
12          // have class Object
13          else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
14             parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
15          }
16          else {
17             parse(bd.getBeanClassName(), holder.getBeanName());
18          }
19       }
20       catch (BeanDefinitionStoreException ex) {
21          throw ex;
22       }
23       catch (Throwable ex) {
24          throw new BeanDefinitionStoreException(
25                "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
26       }
27    }
28 
29    // Execute found DeferredImportSelector
30    // DeferredImportSelector yes ImportSelector A subclass of
31    // ImportSelector Designed to and@Import Annotation has the same effect, but it is realized ImportSelector Classes can conditionally decide to import certain configurations
32    // DeferredImportSelector The design magic of is processed only after all other configuration classes are processed
33    this.deferredImportSelectorHandler.process();
34 }
First, judge whether there is @ Conditional annotation, and then make corresponding Conditional judgment before parsing. Line 9 is equivalent to a local cache. For example, there is a configuration class MyComponentScan at the beginning, which can be injected later through @ Import(MyComponentScan.class). There is no need to process MyComponentScan twice, so the processed configClass should be saved later. To resolve the current class, you need to cycle through the parent class. Entering line 36, the doXxx method starts to parse and process the annotations contained in the current class.
 1 protected void  processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
 2    // Determine whether to skip parsing
 3    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
 4       return;
 5    }
 6 
 7    // When I first entered, configurationClass of size Is 0, existingClass Must be null,Process here configuration repeat import
 8    // If the same configuration class is processed twice, both belong to the configuration class import If the configuration class is not imported, the old configuration class will be removed and the new configuration class will be used
 9    ConfigurationClass existingClass = this.configurationClasses.get(configClass);
10    if (existingClass != null) {
11       if (configClass.isImported()) {
12          if (existingClass.isImported()) {
13             // If the configuration class to be processed configclass The two configured records already exist in the analysis importBy attribute
14             existingClass.mergeImportedBy(configClass);
15          }
16          // Otherwise ignore new imported config class; existing non-imported class overrides it.
17          return;
18       }
19       else {
20          // Explicit bean definition found, probably replacing an import.
21          // Let's remove the old one and go with the new one.
22          this.configurationClasses.remove(configClass);
23          this.knownSuperclasses.values().removeIf(configClass::equals);
24       }
25    }
26 
27    // Recursively process the configuration class and its superclass hierarchy.
28 
29    // Processing the configuration class, because the configuration class may have a parent class(If the full class name of the parent class is java Except for the beginning),All needs will be configClass become sourceClass To parse and then return sourceClass Parent class of.
30    // If the parent class is empty at this time, it will not be while Cycle to resolve. If the parent class is not empty, it will cycle to resolve the parent class
31    // SourceClass The purpose of simple wrapper classes is to handle annotated classes in a unified way, no matter how they are loaded
32    // If you can't understand it, you can treat it as a black box, which won't affect your reading spring Mainstream process of source code
33    SourceClass sourceClass = asSourceClass(configClass, filter);
34    do {
35       // Parsing various annotations
36       sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
37    }
38    while (sourceClass != null);
39 
40    // Store the resolved configuration class, and return to parse Method, the value can be obtained
41    this.configurationClasses.put(configClass, configClass);
42 }
If the current class is modified by @ Component annotation (note that @ Configuration inherits @ component and @ Configuration includes @ component), the internal class will be processed recursively. Note that the external class @ Component annotation recursively calls the internal class parsing, parses the remaining annotations from the innermost class and parses them to the outer layer until the outermost class parses all annotations.
Analyze the current @ PropertySource, load the external configuration file and add it to beanFactory.
Line 37 determines whether the @ ComponentScan annotation is included. If the creation of componentScanParser result set object is included, line 47 calls the parser method of the scanning package to parse.
Line 67 parses the @ Import annotation, imports some additional configuration classes, completes the instantiation of specific classes, and then processes @ ImportResource
For @ Bean processing, please note that it is obtained through asm direct reading bytecode technology. Since it has a standard order, the reflection order will be disordered. Finally, add the processed beanMethod object to configClass, which is implemented by LinkedHashSet.
  1 /**
  2  * Apply processing and build a complete {@link ConfigurationClass} by reading the
  3  * annotations, members and methods from the source class. This method can be called
  4  * multiple times as relevant sources are discovered.
  5  * @param configClass the configuration class being build
  6  * @param sourceClass a source class
  7  * @return the superclass, or {@code null} if none found or previously processed
  8  */
  9 @Nullable
 10 protected final SourceClass doProcessConfigurationClass(
 11       ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
 12       throws IOException {
 13    // @Configuration Inherited@Component
 14    if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
 15       // Recursively process any member (nested) classes first
 16       // Recursively handle the internal class, because the internal class is also a configuration class, which has@configuration Annotation, which inherits@Component,if Judged as true,call processMemberClasses Method to recursively resolve the internal class in the configuration class
 17       processMemberClasses(configClass, sourceClass, filter);
 18    }
 19 
 20    // Process any @PropertySource annotations
 21    // If the configuration class is added@PropertySource Annotation, then parse and load properties File and add attributes to spring In context
 22    for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
 23          sourceClass.getMetadata(), PropertySources.class,
 24          org.springframework.context.annotation.PropertySource.class)) {
 25       if (this.environment instanceof ConfigurableEnvironment) {
 26          processPropertySource(propertySource);
 27       }
 28       else {
 29          logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
 30                "]. Reason: Environment must implement ConfigurableEnvironment");
 31       }
 32    }
 33 
 34    // Process any @ComponentScan annotations
 35    // handle@ComponentScan perhaps@ComponentScans Comments and will scan all under the package bean Convert to filled ConfigurationClass
 36    // Here is what will be customized bean Load into IOC Container, because the scanned classes may also be added@ComponentScan and@ComponentScans Annotation, so recursive parsing is required
 37    Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
 38          sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
 39    if (!componentScans.isEmpty() &&
 40          !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
 41       for (AnnotationAttributes componentScan : componentScans) {
 42          // The config class is annotated with @ComponentScan -> perform the scan immediately
 43          // analysis@ComponentScan and@ComponentScans The class contained in the scanned package of the configuration
 44          // such as basePackages = com.mashibing, Then in this step, you will scan the information under this package and its sub packages class,Then parse it into BeanDefinition
 45          // (BeanDefinition Can be understood as equivalent to BeanDefinitionHolder)
 46          Set<BeanDefinitionHolder> scannedBeanDefinitions =
 47                this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
 48          // Check the set of scanned definitions for any further config classes and parse recursively if needed
 49          // Scan the package through the previous step com.mashibing,It's possible to scan it out bean May also be added to ComponentScan perhaps ComponentScans annotation.
 50          //So we need to iterate through the loop and recurse(parse),Continue parsing until there is no on the parsed class ComponentScan and ComponentScans
 51          for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
 52             BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
 53             if (bdCand == null) {
 54                bdCand = holder.getBeanDefinition();
 55             }
 56             // Determine whether it is a configuration class and set full or lite attribute
 57             if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
 58                // Parsing by recursive method
 59                parse(bdCand.getBeanClassName(), holder.getBeanName());
 60             }
 61          }
 62       }
 63    }
 64 
 65    // Process any @Import annotations
 66    // handle@Import annotation
 67    processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
 68 
 69    // Process any @ImportResource annotations
 70    // handle@ImportResource Annotations, importing spring Configuration file for
 71    AnnotationAttributes importResource =
 72          AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
 73    if (importResource != null) {
 74       String[] resources = importResource.getStringArray("locations");
 75       Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
 76       for (String resource : resources) {
 77          String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
 78          configClass.addImportedResource(resolvedResource, readerClass);
 79       }
 80    }
 81 
 82    // Process individual @Bean methods
 83    // Processing plus@Bean Annotation method, will@Bean Method conversion BeanMethod Object and save it in the collection
 84    Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
 85    for (MethodMetadata methodMetadata : beanMethods) {
 86       configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
 87    }
 88 
 89    // Process default methods on interfaces
 90    // Default method implementation of processing interface, from jdk8 At first, the method in the interface can have its own default implementation, so if the method of this interface is added@Bean Annotations also need to be parsed
 91    processInterfaces(configClass, sourceClass);
 92 
 93    // Process superclass, if any
 94    // Resolve the parent class. If the resolved configuration class inherits a class, the parent class of the configuration class will also be resolved
 95    if (sourceClass.getMetadata().hasSuperClass()) {
 96       String superclass = sourceClass.getMetadata().getSuperClassName();
 97       if (superclass != null && !superclass.startsWith("java") &&
 98             !this.knownSuperclasses.containsKey(superclass)) {
 99          this.knownSuperclasses.put(superclass, configClass);
100          // Superclass found, return its annotation metadata and recurse
101          return sourceClass.getSuperClass();
102       }
103    }
104 
105    // No superclass -> processing is complete
106    return null;
107 }
Parse and set all attribute values included in the annotation, start parsing all classes under the package in line 67, and finally register the scanned class with beanFactory by calling registerBeanDefinition method. Traverse the scanned beanDefinition and recursively resolve it.
 1 public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
 2    // Create corresponding scan class
 3    ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
 4          componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
 5 
 6    // obtain@ComponentScan And set the parameters
 7    Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
 8    boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
 9    scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
10          BeanUtils.instantiateClass(generatorClass));
11 
12    // obtain scopedProxy attribute
13    ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
14    if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
15       scanner.setScopedProxyMode(scopedProxyMode);
16    }
17    else {
18       Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
19       scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
20    }
21 
22    // obtain resourcePattern attribute
23    scanner.setResourcePattern(componentScan.getString("resourcePattern"));
24 
25    // obtain includeFilters attribute
26    for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
27       for (TypeFilter typeFilter : typeFiltersFor(filter)) {
28          scanner.addIncludeFilter(typeFilter);
29       }
30    }
31    // obtain excludeFilters attribute
32    for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
33       for (TypeFilter typeFilter : typeFiltersFor(filter)) {
34          scanner.addExcludeFilter(typeFilter);
35       }
36    }
37 
38    // obtain lazyInit attribute
39    boolean lazyInit = componentScan.getBoolean("lazyInit");
40    if (lazyInit) {
41       scanner.getBeanDefinitionDefaults().setLazyInit(true);
42    }
43 
44    Set<String> basePackages = new LinkedHashSet<>();
45    // obtain basePackages attribute
46    String[] basePackagesArray = componentScan.getStringArray("basePackages");
47    for (String pkg : basePackagesArray) {
48       String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
49             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
50       Collections.addAll(basePackages, tokenized);
51    }
52    // obtain basePackageClasses attribute
53    for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
54       basePackages.add(ClassUtils.getPackageName(clazz));
55    }
56    if (basePackages.isEmpty()) {
57       basePackages.add(ClassUtils.getPackageName(declaringClass));
58    }
59 
60    scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
61       @Override
62       protected boolean matchClassName(String className) {
63          return declaringClass.equals(className);
64       }
65    });
66    // Start scanning and the final scanner is ClassPathBeanDefinitionScanner
67    return scanner.doScan(StringUtils.toStringArray(basePackages));
68 }
Start the package scanning method, traverse the package path, scan the basePackage according to the package name, find all the beandefinitions that meet the requirements, set the properties, register the beanFactory and return.
 1 /**
 2  * Perform a scan within the specified base packages,
 3  * returning the registered bean definitions.
 4  * <p>This method does <i>not</i> register an annotation config processor
 5  * but rather leaves this up to the caller.
 6  * @param basePackages the packages to check for annotated classes
 7  * @return set of beans registered if any for tooling registration purposes (never {@code null})
 8  */
 9 protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
10    Assert.notEmpty(basePackages, "At least one base package must be specified");
11    Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
12    // ergodic basePackages
13    for (String basePackage : basePackages) {
14       // scanning basePackage,Will meet the requirements bean Find all the definitions
15       Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
16       // Traverse all candidate bean definition
17       for (BeanDefinition candidate : candidates) {
18          // analysis@Scope Notes, including scopeName and proxyMode
19          ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
20          candidate.setScope(scopeMetadata.getScopeName());
21          // use beanName Generator to generate beanName
22          String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
23          if (candidate instanceof AbstractBeanDefinition) {
24             // handle beanDefinition Object, for example, this bean Can I automatically assemble to other bean in
25             postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
26          }
27          if (candidate instanceof AnnotatedBeanDefinition) {
28             // Handle general annotations defined on the target class, including@Lazy,@Primary,@DependsOn,@Role,@Description
29             AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
30          }
31          // inspect beanName Has it been registered? If so, check whether it is compatible
32          if (checkCandidate(beanName, candidate)) {
33             // Traverse the current be
34             an of bean Definition and beanName Package into BeanDefinitionHolder
35             BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
36             // according to proxyMode Select whether to create a scope proxy
37             definitionHolder =
38                   AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
39             beanDefinitions.add(definitionHolder);
40             // register beanDefinition
41             registerBeanDefinition(definitionHolder, this.registry);
42          }
43       }
44    }
45    return beanDefinitions;
46 }

 

Topics: source code