The three main processes of initialization

The initialization of the IOC container in Spring is initiated by the refresh() method, which marks the official start of the IOC container. Specifically, this startup consists of three basic processes: Resource location, loading, and registration for BeanDefinition.

Note: This initialization does not include an implementation of Bean dependency injection

Spring separates these three processes, using modules such as ResourceLoader, BeanDefinitionReader, etc., so that users can tailor or extend these processes more flexibly.

  1. Resoure location: Resource location of the BeanDefinition. ResourceLoader is implemented through a unified Resource interface, which provides a unified interface for the use of all forms of The BeanDefinition.
  2. BeanDefinition loading: This loading process represents user-defined beans as data structures inside the IOC container, known as BeanDefinitions.
  3. Registration of BeanDefinition: This is done by calling the implementation of the BeanDefinitionRegistry interface. This registration process registers the BeanDefinitions resolved during loading into the IOC container, essentially injecting them into a HashMap.

BeanDefinition:

In the previous article we introduced the interface definition and implementation of the basic IOC container provided by Spring. On the basis of these spring-provided interface definitions and implementations of the basic IOC container, Spring manages various objects in spring-based applications and their interdependencies by defining BeanDefinitions.

BeanDefinition abstracts our definition of beans and is the primary data type that makes containers work. For IOC containers, BeanDefinition is the data abstraction of the object dependencies managed in the dependency inversion mode, as well as the core data structure of the container to realize the dependency inversion function. The dependency inversion function is completed around the processing of this BeanDefinition.

The Resource location

FileSystemXmlApplicationContext, for example. It loads the XML through the getResourceByPath method and returns a Resource. The template method pattern is used here.

The same method can be found in FileResourceLoader, which comes from FileResourceLoader overriding its parent DefaultResourceLoader, which is defined in the ResourceLoader interface, The respective implementations are provided in FileResourceLoader and DefaultResourceLoader. This is called in the getResource method of DefaultResourceLoader:

This is indeed the template method pattern, where subclasses override the parent class implementation. And by looking for the method call, the first is to look at the FileSystemXmlApplicationContext loadBeanDefinitions method, this method is realized in AbstractXmlApplicationContext:

At this point has been injected with the corresponding in AbstractXmlApplicationContext BeanDefinitionReader, call the reader loadBeanDefinitions method again, After into the AbstractBeanDefinitionReader class, achieved here:

Here you can see that a ResourceLoader was injected into BeanDefinitionReader, and here you can see that the getResource method was called to the ResourceLoader, which completes the traceability of the method

Be aware that FileSystemXmlApplicationContext itself is a DefaultResourceLoader subclass, The getResource FileSystemXmlApplicationContext is actually to the parent class as a template method call.

So where is the FileSystemXmlApplicationContext defines the reader BeanDefinition BeanDefinitionReader and complete the BeanDefinition read?

BeanDefinition load

To return to the IOC container first initialize the entrance, also is to have a look at the refresh method, this method was originally in the FileSystemXmlApplicationContext constructor is called, it calls marked the beginning of the container initialization, These initialization objects are BeanDefinition data.

Refresh is an important method for starting a container. The method is found in AbstractApplicationContext class, it detailed describes the ApplicationContext initialization process.

We went to see the base class AbstractRefreshableApplicationContext FileSystemXmlApplicationContext is how to achieve. First look at his refreshBeanFactory method:

First create the need to inject DefaultListableBeanFactory, then call loadBeanDefinitions to load resources into its holdings of the BeanFactory, and this method is an empty implementation in the class, subclass left to do the corresponding implementation. In AbstractXMLApplicationContext, we find the corresponding specific implementation:

Here you can clearly see the reader to create and configure, injected BeanDefinitionReader here AbstractXMLApplicationContext DefaultListableBeanFactory as parameters, but pay attention to, Its injection is in the form of a BeanDefinitionRegistry interface:

The parent class AbstractBeanDefinitionReader constructor:

If the passed BeanFactory implements only BeanDefinitionRegistry, inject it, if ResourceLoader is also implemented, use it as the default ResourceLoader, if EnvironmentCapable is implemented, It’s going to load in its internal environment. Then we go back to the XMLBeanDefinitionReader subclass, which overrides the loadBeanDefinitions method without using the parent class’s implementation

Here the doLoadBeanDefinition method is called:

This method consists of two steps: one is to load the DOM and the other is to register the BeanDefinition from the DOM into the BeanFactory.

In registration method, was conducted by invoking BeanDefinitionDocumentReader, actual call its implementation class DefaultBeanDefinitionDocumentReader, In its approach and by its holdings of BeanDefinitionParserDelegate.

To summarize the process: As you can see, in the process of initialization FileSystemXMLApplicationContext is by calling the refresh of the IOC container to start the whole process of BeanDefinition load, This initialization is done with the defined XMLBeanDefinitionReader. At the same time, we also know that actually use the IOC container is DefaultListableBeanFactory, specific Resource loading on XMLBeanDefinitionReader read BeanDefinition implementation. In the implementation of XMLBeanDefinitionReader as you can see, is in the reader. The loadBeanDefinition BeanDefinition began in load, While his father class AbstractBeanDefinitionReader already ready for BeanDefinition load.

The loadBeanDefinitions (Resource Res) method is called, but this method is not implemented in this class; it is implemented in XMLBeanDefinitionReader. In the reader, we need to get the Resource that represents the XML file. Because this Resource object encapsulates the I/O operation on the XML file, the reader can get the XML file object after opening the IO stream. Once we have this file object, This XML document tree can be parsed according to Spring’s Bean definition rules.

The loading of BeanDefinition is split into two parts, with the Document objects first obtained by calling the XML parser, but these objects are not parsed according to Spring’s Bean rules. After the general XML parsing is completed, it is the place to parse according to Spring Bean rules. This process of parsing according to Spring Bean rules is implemented in DocumentReader. Use the default DefaultBeanDefinitionDocumentReader here. The DefaultBeanDefinitionDocumentReader creation is completed in the latter method, and then complete BeanDefinition processing, by processing the BeanDefinitionHolder object to hold. In addition to holding the BeanDefinitionHolder object, this BeanDefinitionHolder also holds other information related to the use of beanDefinitions, such as the Bean’s name, a collection of aliases, and so on. BeanDefinitionHolder generation is done by parsing the content of the Document Document tree, You can see the parsing process is implemented by BeanDefinitionParserDelegate (specific in the above processBeanDefinition method).

The parsing process: call the delegate parseBeanDefinitionElement method:

Parse the bean element in detail in the highlighted line:

Inside is the analysis of various elements, too fine later slowly look.

After this layer by layer parsing, the BeanDefinition we defined in the XML file is loaded in its entirety into the IOC container, where the data mapping is established. The corresponding data structures, or abstractions of POJO objects in the IOC container, are established in the IOC container. These data structures can use AbstractBeanDefinition as an entry point for the IOC container to perform indexes, queries, and operations. After the above process, the IOC container has roughly completed the data preparation of the management Bean object. However, significant dependency injection has not actually occurred at this point. For now, the IOC container BeanDefinition only has static configuration information. Strictly speaking, the container is not fully functional at this time. To fully play the role of the container, data registration to the container needs to be completed.

Registration of BeanDefinition

After the loading and parsing of BeanDefinition is completed, the user-defined BeanDefinition information has established its own data structure and corresponding data representation in the IOC container, but these data cannot be directly used by the IOC container at this time. This BeanDefinition data needs to be registered in IOC. In DefaultListableBeanFactory, is held by a HashMap BeanDefinition load, the definition of the HashMap in DefaultListableBeanFactory can see.

The process of registering the parsed BeanDefinition with the MAP in the IOC container is carried out after loading the BeanDefinition. The call process is as follows:

In the concrete implementation: DefaultBeanDefinitionDocumentReader:

BeanDefinitionReaderUtils:

Call into the registry (namely DefaultListableBeanFactory) : see the DefaultListableBeanFactory registerBeanDefinition method:

Register here and you’re done.