current position:Home>Spring IOC container loading process

Spring IOC container loading process

2022-01-26 21:55:28 Roy4259

IOC Container loading process

Spring Common ways to load context are xml、 Two ways of annotation ,xml The coupling degree is high , We use annotations to create context

  1. Instantiate container
  2. Instantiation Bean factory
  3. Instantiation BeanDefinition Reader
  4. Instantiation BeanDefinition Scanner for
  5. Register the configuration class as BeanDefinition
  6. call refresh() Method ( Show only key methods )
    • invokeBeanFactoryPostProcessors(beanFactory)
    • finishBeanFactoryInitialization(beanFactory)

1. Instantiate container

see AnnotationConfigApplicationContext Construction method of

2. Instantiation Bean factory

this() Method calls the parent class GenericApplicationContext Empty construction method of You can see that a factory class is initialized DefaultListableBeanFactory( The most versatile Bean Factory )

3. Instantiation BeanDefinition Reader

go back to AnnotationConfigApplicationContext Empty construction method of A reader is initialized :AnnotatedBeanDefinitionReader read, A scanner ClassPathBeanDefi nitionScanner scanner;scanner It's not very useful , It's just a manual call outside of us .scan Wait for the method to work , The normal way is not to use it scanner Object's ;

To follow up this.reader = new AnnotatedBeanDefinitionReader(this); Method

To follow up AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); How to find registerAnnotationConfigProcessors Method , I found that there will be many registrations inside Bean Definition ( It's all a guarantee Spring IOC The container corresponds to the basic class whose function can work normally ), such as ConfigurationClassPostProcessorAutowiredAnnotationBeanPostProcessor etc. Because the code is too long, only fragments are intercepted here to glance at registerPostProcessor Method ( This class will be BeanDefinition Put it in a container , Of other basic classes BeanDefinition It is also registered in the container ) Follow up to registry.registerBeanDefinition(beanName, definition); In the method , Discovery is an interface class , View his implementation class DefaultListableBeanFactory( Remember the factory class that first called the constructor to initialize , Of course you can too debug have a look ), The method is longer , See the key lines below , take BeanDefinition Put in a map in ,beanName Put it into a list in ( These two properties beanDefinitionMapbeanDefinitionNames Very often )

4. Instantiation BeanDefinition Scanner for

Because the general use way is not used AnnotationConfigApplicationContext Inside scanner Of , there scanner Just so the programmer can call it manually AnnotationConfigApplicationContext Object's scan Method . So I'm not going to look at it here scanner How is it instantiated .

As follows context.scan("com.roy") Method scanning package will use this scanner , And by @ComponentScan("com.roy") Annotation will reinitialize a scanner for scanning


Summarize the above this() What methods have done : Create context objects AnnotationConfigApplicationContext Initialized a bean Factory , Create a reader AnnotatedBeanDefinitionReader Many basic classes have been registered when BeanDefinition; We'll instantiate them later , And call their functions ( For example, load the configuration class and register it in our container )

Keep going down , notice register(componentClasses); Method , This method will register the configuration class we passed in as BeanDefinition.

5. Register the configuration class as BeanDefinition

thorough register(componentClasses); This method , The incoming configuration class will be registered circularly Continue to look at registerBean Method , Will enter the doRegisterBean In the method 1' AnnotatedGenericBeanDefinition It can be understood as describing BeanDefinition Class , It can convert the passed in annotated class into AnnotatedGenericBeanDefinition class , call getMetadata Method can get the annotation on the class ;

2' conditionEvaluator.shouldSkip(abd.getMetadata()) Determine if you need to skip the registration , I went in and found that it was an inspection @Condition annotation , If you don't do that , Will skip the registration of this class ;

3' Set scope , If it's not set , The default is singleton ;

4' obtain beanName;

5' AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); Parse general annotations , Set to AnnotatedBeanDefinition in , Trace in and find that the parsed annotation is @Lazy,@Primary,@DependsOn,@Role,@Description;

6’ Processing qualifier , Among them @Qualifier , @Primary , @Lazy Annotations also need to be set to AnnotatedGenericBeanDefinition abd in ;

7' hold AnnotatedGenericBeanDefinition Data structure and beanName Encapsulated in an object ;

8' BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry); Will eventually call DefaultListableBeanFactory Medium registerBeanDefinition Method to register , It will eventually be put into what I said before beanDefinitionMapbeanDefinitionNames in ;

thus , The incoming configuration class has been registered Spring In the container

6. call refresh() Method instantiation this() Base class in method , Then call their interface scan package to register. BeanDefinition To Spring In the container

First understand BeanDefinitionRegistryPostProcessor Follow BeanFactoryPostProcessor Two interfaces .

BeanDefinitionRegistryPostProcessor You can register beanDefinition BeanFactoryPostProcessor You can modify the registered beanDefinition These two interfaces will be invokeBeanFactoryPostProcessors(beanFactory) In the called , this() Method , ConfigurationClassPostProcessor It inherits the above two interfaces at the same time , He is spring The most important post processor in , The following specific analysis .

notice refresh() Method

about IOC Focus on invokeBeanFactoryPostProcessors(beanFactory);finishBeanFactoryInitialization(beanFactory); Two ways

Check out invokeBeanFactoryPostProcessors(beanFactory); In the way , Be careful getBeanFactoryPostProcessors() Active call addBeanFactoryPostProcessor Method BeanFactoryPostProcessor

6.1 Get into invokeBeanFactoryPostProcessors Method

 *invokeBeanFactoryPostProcessors The overall process of : 
 * call bean The factory's postprocessor
 * 1)BeanDefinitionRegistryPostProcessor( First executed )
 *    be-all bean The definition information will be loaded into the container ,Bean The instance has not been initialized yet
 * 2)BeanFactoryPostProcessor( After execution )
 *    be-all Bean The definition information has been loaded into the container , however Bean The instance has not been initialized yet .
 *  The purpose of this method is to ioc Container loading bean Before and after definition
 * BeanDefinitionRegistryPostProcessor yes bean Definition before parsing
 *     1) Realized PriorityOrdered Interface
 *     2) Realized Ordered Interface
 *     3) There is no implementation of any priority interface
 *     4) because BeanDefinitionRegistryPostProcessor yes BeanFactoryPostProcessor The child interface of the interface , Realization BeanFactoryPostProcessor Methods
 * BeanFactoryPostProcessor yes bean Define after analysis call
 *     1) Realized PriorityOrdered Interface
 *     2) Realized Ordered Interface
 *     3) There is no implementation of any priority interface

1' Determine the incoming factory beanFactory Is there any realization BeanDefinitionRegistry , The implementation indicates that there is registration BeanDefinition The ability of , You need to call BeanDefinitionRegistryPostProcessor Of postProcessBeanDefinitionRegistry Method , Call again BeanFactoryPostProcessor Interface method postProcessBeanFactory , If not , Call directly BeanFactoryPostProcessor Interface method postProcessBeanFactory ;

1'' Loop to manually create incoming beanFactoryPostProcessors ( It is generally empty , need AnnotationConfigApplicationContext.addBeanFactoryPostProcessor Show add ), Check whether there is implementation BeanDefinitionRegistry , If there is , Call his postProcessBeanDefinitionRegistry Method , Then add it to a saved BeanDefinitionRegistryPostProcessor Set list registryProcessors in ( All objects in this collection have been executed postProcessBeanDefinitionRegistry Methods , But not implemented postProcessBeanFactory Of BeanDefinitionRegistry, It will be called and executed uniformly at the end postProcessBeanFactory Method ), If not , Will execute regularPostProcessors.add(postProcessor); Add to BeanFactoryPostProcessor Set list regularPostProcessors in ;

2'' Define a list Save the currently created BeanDefinitionRegistryPostProcessor , Find by type beanName , Find out the implementation in turn PriorityOrdered , Ordered And those that do not implement any priority interfaces BeanDefinitionRegistryPostProcessor , There is a need to implement the priority interface , Finally, call them. postProcessBeanDefinitionRegistry Method , It should be noted that , Find out by type beanName This operation , You need to query again every time , because BeanDefinitionRegistryPostProcessor Can create BeanDefinition Of ;

3'' Call complete postProcessBeanDefinitionRegistry Of registryProcessors Collection and its own incoming regularPostProcessors Would call postProcessBeanFactory Method .

2' Get all types from the container as BeanFactoryPostProcessor Of beanName, Find out the implementation in turn PriorityOrdered , Ordered And those that do not implement any priority interfaces BeanFactoryPostProcessor, The priority interface needs to be sorted , Finally, call them. postProcessBeanFactory Method .

Roughly complete the overall process of this method , Then the configuration class (@Configuration@Component etc. ) How is it loaded into spring What about the containers , This can not do without ConfigurationClassPostProcessor This class , It is the key to scan configuration classes and inject configuration into containers , To see it come true BeanDefinitionRegistryPostProcessor Interface , and BeanDefinitionRegistryPostProcessor The interface inherits BeanFactoryPostProcessor, therefore ConfigurationClassPostProcessor Will call in turn postProcessBeanDefinitionRegistrypostProcessBeanFactory Two methods . Now let's analyze ConfigurationClassPostProcessor The method in

6.1.1 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry

To see ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry Method , Would call processConfigBeanDefinitions Method 1'' Get IOC All currently in the container bean Definition name , Put in candidateNames Array ;

2'' loop candidateNames Array , according to beanName Get BeanDefinition, Judge whether it has been handled ( Judge according to a certain attribute , It will not be set until it is resolved );

3'' Determine whether it is a configuration class , If yes , Add to configCandidates Array ; When judging , Also marks that the configuration class belongs to Full Configuration class , still Lite Configuration class , Explain their differences ;

1.  When registering a configuration class , Can not add @Configuration annotation ,
Use it directly @Component @ComponentScan @Import @ImportResource Etc ,
Spring Call this configuration class Lite Configuration class , 
If you add @Configuration annotation , It's called Full Configuration class . 
2.  If you register Lite Configuration class ,getBean This configuration class , You will find that it is the original configuration class ,
If you register Full Configuration class ,getBean  This configuration class , You will find that it is no longer the original configuration class ,
It has been cgilb Class of agent . 
3.  Write a A class , There is a construction method , Print out “ Hello ”, Write another configuration class ,
There are two quilts in it @bean Method of annotation , One way new 了 A class ,
And back to A The object of , Call this method getA, The second method calls again getA Method ,
If the configuration class is Lite Configuration class , You'll find it printed twice “ Hello ”,
in other words A Class quilt new Twice , If the configuration class is Full Configuration class ,
You'll find that it's only printed once “ Hello ”, in other words A Classes are only new Once ,
Because this class is cgilb Agent , Method has been overridden .

4'' If candidateNames Empty in middle ( No configuration class ), Go straight back to

5'' Yes candidateNames Conduct Order Sort

6'' Create configuration class parser object and parse configuration class , Loop parsing configuration class parser.parse(candidates);

1''' see parse Method , View the first... In annotation mode if Branch

2''' Look at the call chain , It is found that the configuration class is not directly registered as BeanDefinition , But joined a configurationClasses Of map in ( In step 7, uniformly register as BeanDefinition), Get into doProcessConfigurationClass See how it is parsed

1'''' Handle @PropertySource annotation , @PropertySource Annotations are used to load properties file

2'''' get ComponentScan Note specific content ,ComponentScan Note except for the most commonly used basePackage outside , also includeFilters ,excludeFilters etc. .

3'''' Judge whether there is @ComponentScans Mark , Or be @Condition Mark , If so

1.  Perform scan operation , Put the scanned in set, This method will be explained in detail later .
2.  loop set, Determine whether it is a configuration class , If yes , Recursively call parse Method , Because the scanned class ,
Or a configuration class , Yes @ComponentScans annotation , Or some of them @Bean Method of marking
wait , So it needs to be parsed again .

Enter into doScan Method Put the documents that meet the requirements , Convert to BeanDefinition The last one will BeanDefinition Register in container (@ComponentScan Will be immediately registered in the container , Others will be in step 7 (7'') Unified registration )

4'''' Handle @Import annotation

@Import There are three situations 
①Import  General class
②Import ImportSelector
③Import ImportBeanDefinitionRegistrar
1.  loop importCandidates, Determine which situation 
2.1  If it's a normal class , It's going to get into else, call processConfigurationClass Method ,
processImports This method is based on processConfigurationClass Called in method
processImports Active call again processConfigurationClass Method ,
Is a recursive call , because Import General class of , It could have been added Import annotation ,
@ComponentScan Notes or other notes , So ordinary classes need to be parsed again
If Import ImportSelector It's the first one if In the middle ,
First, execute Aware Interface method , So in the realization of ImportSelector At the same time ,
It can also be realized Aware Interface and then judge whether it is DeferredImportSelector,
DeferredImportSelector Expanded ImportSelector
If not , call selectImports Method , Get the fully qualified class name array ,
Convert to an array of classes , Then call processImports, What's more, it's a recursive call ...
There may be three more situations , One situation is selectImports The class of is a common class ,
2.2  The second situation is selectImports The class of is a ImportBean DefinitionRegistrar class ,
2.3  Is the third situation the same ImportSelector class ... So we need to call recursively
If Import ImportBeanDefinitionRegistrar And I ran to the second one if,
It will still be executed Aware Interface method , There's no recursion here , Will put the data in ConfigurationClass Medium
Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> importBeanDefinitionRegistrars In the middle

5'''' Handle @ImportResource annotation

6'''' Handle @Bean Methods , You can see that you get the @Bean After the method of , Not immediately BeanDefinition , It's about using one first set receive

7'' this.reader.loadBeanDefinitions(configClasses); Unified registration Bean

6.1.2 ConfigurationClassPostProcessor#postProcessBeanFactory

 Determine whether the configuration class is Lite Configuration class , still Full Configuration class , If it is a configuration class , Will be Cglib agent 

1' Judge whether the current post processor method has been called -> No,

2' Judge whether it has been executed processConfigBeanDefinitions Method -> Once executed, it will not be repeated ( because ConfigurationClassPostProcessor It has its own realization postProcessBeanDefinitionRegistry, Called above , This is used to handle lazy loading )

3' Use cglib Proxy the configuration class

 Only full Version configuration class will be created cglib agent 
Although it is not marked when specifying the configuration @Configuration It's OK , So here's the difference between adding annotations and not
added @Configuration What is the essential difference between and without ?
When in a configuration class @Bean  Use the method to reference another Bean If you don't annotate it, it will be loaded repeatedly Bean
If you add @Configuration   Will be created here cglib agent , When calling @Bean Method will first detect whether there is in the container

The general flow chart is as follows The configuration class is Lite still Full This step is to (6.1.1) Calling method postProcessBeanDefinitionRegistry in processConfigBeanDefinitions Resolved , Intercept some key codes Follow up ConfigurationClassUtils.checkConfigurationClassCandidate() Method

4' add to BeanPostProcessor Post Processors : Add to proxy class BeanFactory attribute

6.2 Get into finishBeanFactoryInitialization Method

 This method instantiates all the remaining ( Non lazy loading ) Single case ;
such as invokeBeanFactoryPostProcessors Method according to various annotations , It will be initialized at this time ; 
The instantiation process is various BeanPostProcessor Start working . 
This method is used to instantiate lazy loading singletons Bean Of

I drew a simple picture , involves bean Life cycle of , I will analyze it in detail later

copyright notice
author[Roy4259],Please bring the original link to reprint, thank you.

Random recommended