1. The description of the IOC
What is 1.1?
Two concepts: inversion of control and dependency injection
Consider the traditional way of doing things: based on the principle of single responsibility for objects, it is rare for an object to do its job without relying on other objects, so this is where dependency between objects comes in. In our development, we create objects whenever we need them, and the control of object creation is in our own hands. When too many objects are created, an object change occurs, and you have to change all the objects that depend on it. At the same time, the object coupling is serious. About Spring, xiaobian also organized a set of Spring family bucket learning notes, which contains the web’s hottest spring problems summary.
- At this point, we wonder if we can just grab the object and use it when we use it, and hand over the ability to create the object to a third party, so we don’t have to care about how the object was created. About to relinquish control. This is called inversion of control
- At this point, another question arises, how can objects be directly used by us? When the object is created, we inject this object into this object, and then we can use it. This is dependency injection
- Another question, how is coupling solved? With inversion of control we only use the object, and if the object is changed, we only need to change the way a third party creates the object. Is there still object coupling?
2. The IOC architecture
This is the IOC’s architectural idea, not its implementation flowchart.
Let’s go through it step by step.
Vernacular version 2.1
In chapter 1, we learned that IOC is there to help us manage and create objects.
At this point we need a container to hold the information we need to create, namely the XML or annotations in the diagram, so once we have our own BeanDefiniton information, we need an interface to read this information. Hence the BeanDefinitionReader for reading our own Bean information.
So we need to think about the question, how can we produce so many objects?
The answer is the factory model. Spring is the default factory DefaultListableBeanFactory, yes, all the objects in the Spring (container objects and objects created by our own) were created by him. Mass production of objects
We don’t want to produce directly through the BeanFactory, we need to do some specific processing on the factory, so there’s the BeanFactoryPostProcessor, which does some specific processing on the factory. We can customize the BeanFactory ourselves by implementing this interface. I want to create my favorite objects individually, arrange, and a FactoryBean is born to help us create the object we need (Part 4 explains the difference between them in detail).
I want unity objects to do some special things my way before they are created, simple, arranged: see_no_EVIL
The BeanPostProcessor comes along, providing two methods: one that executes the internal Before method After the object is instantiated and Before it is initialized, and the After method After the initialization. (Bean life cycle, Part 4)
BeanPostProcessor is executed before the object is created. The Before method is executed after creation.
If you’re familiar with the concept of instruction reorder, you’ve probably heard of a case where it takes three steps to create an object
- Create space (instantiation)
- Initialize the
- The assignment
Instruction reordering occurs during initialization and assignment
Based on this point, you should be able to get to a point, instantiation is not the same as initialization.
So that brings us to the point where we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean.
So BeanPostProcessor’s before method is executed after instantiation and before initialization.
After all the previous operations, our object is finally in our pocket (container).
In the case of destruction, the method is usually not available through the ApplicationContext, but only through its subclasses. The same process for destruction is to perform an operation before destruction and then destroy.
Instruction reordering occurs during initialization and assignment
Based on this point, you should be able to get to a point, instantiation is not the same as initialization.
So that brings us to the point where we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean, and we’re going to do something to the Bean.
So BeanPostProcessor’s before method is executed after instantiation and before initialization.
After all the previous operations, our object is finally in our pocket (container).
In the case of destruction, the method is usually not available through the ApplicationContext, but only through its subclasses. The same process for destruction is to perform an operation before destruction and then destroy.
2.2 Actual workflow
Anyone who has seen or heard the Spring source code knows that there is a method called Refresh that does a lot of things. Of course, his behavior also represents the entire IOC container process of loading and instantiating objects. We’ll take a closer look at chapter 3 code interpretation
Execution process:
- Load the configuration file and initialize the Environment interface
- Prepare the context and initialize some configuration resources
- Create a factory
- Add various environments for the factory
- Gets the BeanFactoryPostProcessor overwritten by the subclass itself
- Implement the container and our own BeanFactoryPostProcessor
- Registered BeanPostProcessor
- Internationalization processing
- repeater
- The subclass initializes the Bean
- Register listener, observer mode
- Complete Bean creation
- Publish the corresponding event, listener
3. IOC source code interpretation
3.1 Context Configuration startup
At the time of creating ClassPathXmlApplicationContext, carried out by the constructor methods.
In plain English, a loader that resolves the configuration file path is loaded; Then the system environment variables to get the configuration file, some configuration file to remove space, conversion expressions and other operations (not parsing); And finally, that thing that I’ve highlighted in red, in the Refresh method, it does almost all of the work. The following fine chat
3.2 the refresh
This method does almost everything, creating factories, executing processors, etc., instantiating objects, enabling event listening, etc.
Let’s talk more about that
3.3.1 prepareRefresh ()
The main purpose of this method is to prepare for the refresh of the application context. Verify resource files, set startup time and active status, etc.
3.3.2 rainfall distribution on 10-12 obtainFreshBeanFactory ()
BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory = BeanFactory
This is the process of loading the configuration file, note: there is still no parsing at this point, parsing is marked in red below
The parse process comes from Parse, which calls the Java library for parsing XML directly, and returns a Document object.
Through the Document object, read the internal tag, execute different methods, logic and MyBatis parsing configuration file idea is the same, we read by ourselves.
At this time all the Bean definition information is saved by BeanDefinitionRegistry interface, and then walk a subclass DefaultListableBeanFactory factory registration method
3.3.3 prepareBeanFactory (the beanFactory)
Prepare some environments for the BeanFactory to use during instantiation, and add the container’s own BeanPostProcessor
3.3.4 postProcessBeanFactory
BeanFactoryPostProcessor for subclass extensions,
3.3.5 invokeBeanFactoryPostProcessors (the beanFactory)
This is a class that involves two interfaces.
- BeanFactoryPostProcessor
- BeanDefinitionRegistryPostProcessor interface, this interface is spring BeanFactoryPostProcessor interface, its priority is higher than spring BeanFactoryPostProcessor
Its overall execution flow is: perform BeanDefinitionRegistryPostProcessor spring BeanFactoryPostProcessor first, and then execute spring BeanFactoryPostProcessor
This is the process of the BeanDefinitionRegistryPostProcessor interface
BeanFactoryPostProcessor processing logic
The general logic is to categorize first, skip the ones that have already been processed, categorize the ones that haven’t been processed, and the logic is the same as above.
3.3.6 registerBeanPostProcessors
The logic of this method is the same as above, except that BeanFactoryPostProcessor is implemented directly, whereas this registration is not implemented.
First get all the BeanPostProcessor type beans in the factory, then sort and register them.
3.3.7 initMessageSource ()
Implementing internationalized content
3.3.8 initApplicationEventMulticaster
A multicast is created to provide support for adding listeners.
Main logic:
- Whether there is applicationEventMulticaster container, if there is a direct registration
- If not, create a SimpleApplicationEventMulticaster, register into the container.
3.3.9 onRefresh ()
Subclasses extension
3.3.10 registerListeners ()
Implementation of the observer pattern
3.3.11 finishBeanFactoryInitialization
There is too much to cover in this section, so it is explained in code and diagrams.
The following figure shows the main process for creating a Bean
Say it one by one according to the number in the picture:
- Whether beanDefinitions need to be merged. BeanDefinition encapsulates beans into different Bean information definition classes depending on the type of configuration file information. GenericBeanDefinition, the configuration file version we use; ScannedGenericBeanDefinition annotation scanning version, and so on.
And in this process, the parent definition and the child definition, we need to combine them when we actually deal with the definition information, and there are three main aspects
- There is parent definition information, which is used to create a RootBeanDefinition and pass in the custom information as a parameter.
- There is no parent definition information, and the current BeanDefinition is RootBeanDefintion, returns a clone of RootBeanDefintion
- There is no parent definition information, and the current BeanDefintion is not of RootBeanDefintiton type, returns a RootBeanDefintion built directly from that BeanDefintion
The above flow is also the execution flow in the source code
- IsFactoryBean. Determines whether it is a FactoryBean
** A quick recap: ** FactoryBeans allow developers to create their own Bean interfaces. Three methods are provided internally
When we direct the Bean through GetBean, we get the Bean type that the factory specified to return. If you want to get the Bean itself, you get & with a prefix
One more point, this is the main way to get beans from the container, and the logic that resolves loop dependencies
How does it deal with circular references?
It introduces the concept of a three-level cache
When a circular reference occurs, it first creates the Bean through the ObejctFactory, and ** the object is not assigned attributes, only space is created in the heap. ** The Bean is then added to the earlySingletonObjects container, which means that the Bean stored in this container is a semi-finished Bean. ** In subsequent attribute assignments, since the object is singleton, its reference address does not change, that is, the object is complete.
1. The getBean. This method creates all objects directly, which is the core method of Spring. Let’s take a look at the overall flow
Its main logic is:
- Get the real name of the Bean currently being instantiated, mainly to process the FactoryBean. Once you get it, check the current container to see if the Bean has been created, and return it if it has.
- If not, get the parent factory. If the parent factory is not empty and there is no information about the current Bean in the current container, then try to get the Bean definition information from the parent factory and instantiate the Bean
- If the parent factory is empty, the current Bean information is stored in the alreadyCreated cache.
- Gets the current Bean merge information (getMergedLocalBeanDefinition), view the current Bean exists dependence, if there is to judge whether the current Bean and rely on the Bean as the circular dependencies, if not circular dependencies are first create depend on the Bean
- Determine the scope of the current Bean.
- If the current Bean is a singleton object, create the Bean instance directly
- If the current Bean is a multi-instance object, the current Bean information is added to the creating multi-instance cache and removed after creation
- If the current Bean is of another type, such as Requtst, Session, etc., then customize an ObejctFacotry factory, override the getObject method, and create the object
- After the object is created, determine whether the current object is the object you need, if it is directly returned; If the type conversion fails, throw an exception
Take a look at the execution of CreateBean
The main thing this method does is get the corresponding Class object from the Bean name; If the Class object fetched by the current Bean is not empty and the RootDefintiton can fetch the Bean directly, clone a copy of the Bean definition information for later use.
Verify the @Override information on the current Bean. Execute BeanPostProcessor to return a proxy object (if one exists), or create the Bean directly if none exists
Let’s talk about this stuff – resolveBeforeInstantiation next
Go ahead, take a look at the preprocessor logic
The post-processor doesn’t look at it, it just calls all the post-processors, and then executes it, no more logic.
Let’s move on to doCreateBean
Its general process is as shown in the figure above:
Then check the FactoryBean cache to see if there is a Bean being created, pull it out if there is one, and create a wrapper class instance of the current Bean if not. Then take the instance and instance type of the class, and execute the post-processor.
Whether the current Bean is a singleton and allows circular dependencies while it is being created, and if so, create an ObejctFactory for the current Bean to solve the problem of circular dependencies
Instantiate the Bean by populating the Bean’s properties.
See if the Bean is present in the early container cache (the second level cache in the cache). If yes, a cyclic dependency exists and is processed
Let’s start with circular dependencies
Now, createBeanInstance
Spring provides three ways to create wrappers for objects:
- Created directly from the provider object object. obtainFromSupplier
- Created directly through the factory method.
- Created by default. Constructor does not require automatic injection. The constructor calls the default constructor
Once this method is done, you should know that the object instance has been created, and all that is left is to perform a series of enhancers and initializers, property populations, and so on.
We follow the code execution order, with the property population called populateBean
This method executes logic:
- First, check whether the Bean passed in is NULL. If it is null, check whether there is an attribute value in the Bean definition information. If there is an exception. If there is no skip
- The current Bean defines whether the information is combined, and if it is at this point InstantiationAwareBeanPostProcessors exist in the factory, then modified beans before fill information
- Get all the attribute values, parse the auto-injection mode of the attribute values, Type or Name, and perform auto-injection
- Determine whether there is any InstantiationAwareBeanPostProcessors, modify before set of properties
- Check whether a dependency check exists and check dependencies
- Attribute assignment
The next step is to execute the initialization method, which is to call BeanPostprocessor, init, etc
So this is the flow diagram of how to execute this method, and by this point you should have an idea of why BeanPostProcessor’s before method is executed in init. The purpose of this method is simply to print a lifetime of objects that have already been created.
Let’s look at the destruction method. registerDisposableBeanIfNecessary
For singleton beans,Spring stores the beans that need to be destroyed to the disposableBeans cache, which wraps the destruction Bean with the DisposableBeanAdapter
For other scopes, the destruction callback function is customized, but it will finally be encapsulated as DisposableBeanAdapter
In encapsulation to DisposableBeanAdapter, you will first determine whether the destroy method is present in the Bean, and then assign a value to the destroyMethodName variable. Again, judge the method’s arguments and throw an exception if the number of arguments is greater than 1
3.3.12 finishRefresh
This method performs a series of resource cleanups and
InitLifecycleProcessor this method is as simple as checking to see if there is a lifecycle processor in the current Bean. If there is one, use it directly. If not, create a default one and register it as a singleton and throw it into the container. Forward + pay attention to get xiaobian collated good micro service family bucket learning notes!
The last
Like xiaobian today’s share, remember to follow me to like yo, thank you for your support! Important things say three times, forward + forward + forward, must remember to forward attention oh!!