Note 1: spring source code is based on spring3.1
NOTE 2: Refer to spring technology insider Version 2
1. Spring IoC container Initialization
Spring IoC container initialization includes three basic processes: beandefinition resource locating, loading, and registration. Before analyzing these three processes, we need to note that spring separates these three processes and completes them using different modules. This makes the Spring IoC container more flexible.
Resource Positioning
Here, resource refers to beandefinition's resource location. It is implemented by resourceloader through a unified resource interface and provides a unified interface for various beandefinition forms. For example, the bean definition information in the file system can be abstracted using filesystemresource, and the bean definition information in the class path can be abstracted using classpathresource.
This resource positioning process is actually the process in which the IOC container looks for bean-defined data.
For more information about resource in spring, here is a blog: http://blog.csdn.net/zhangyihui1986/article/details/8793626
Beandefinition Loading
This loading process represents the defined bean as the data structure beandefinition inside the container. This beandefinition is actually the abstraction of pojo objects in the IOC container. Through the data structure defined by beandefinition, the IOC container can conveniently manage pojo objects, that is, beans.
Register beandefinition with the IOC container
This process is completed by calling the beandefinitionregistry interface. This registration process registers the parsed beandefinition in the loading process to the IOC container. In fact, the IOC container injects beandefinition into a hashmap. The IOC container uses this hashmap to hold the beandefinition data.
Additional instructions
Note that the IOC container initialization process does not include the implementation of dependency injection. In spring design, bean-defined loading and dependency injection are two independent processes. Dependency injection usually occurs when the application requests a bean instance from the container through getbean for the first time. One exception is that when we specify the lazyinit attribute (pre-instantiation configuration) in the bean definition, the bean dependency injection is completed during the initialization of the IOC container, it is not triggered when the bean is obtained for the first time after initialization.
Next we will analyze the first step in IOC container initialization process-resource locating from the source code.
2. Resource Positioning
Source code analysis starts with the filesystemxmlapplicationcontext class, because in spring technology insider, this class is used as the starting point to describe the initialization of IOC containers, so that some theories and code explanations in the book can be referenced.
If defaultlistablebeanfactory is used programmatically, the following method is used:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();Resource resource = new FileSystemResource("xxx.xml");XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);reader.loadBeanDefinitions(resource);
We need to create a filesystemresource (or other resources such as classpathresource) to locate the resource. The resource here cannot be used directly for defalistlistablebeanfactory, but through beandefinitionreader (The implementation class xmlbeandefinitionreader is used in the above example) process the information.
One of the advantages of using applicationcontext over using defaultlistablebeanfactory is that applicationcontext has provided a series of functions for loading different resources, all applicationcontext in spring implements the resourceloader interface (the base class abstractapplicationcontext inherits the defaultresourceloader, and defaultresourceloader is the default implementation class of the resourceloader interface ).
Filesystemxmlapplicationcontext Inheritance System
Let's take a look at the inheritance system of filesystemxmlapplicationcontext from the perspective of spring source code and UML class diagrams:
From the inheritance system, we can see that filesystemxmlapplicationcontext has the ability of resourceloader to read beandefinition defined in the form of resource by inheriting abstractapplicationcontext. Because the base class of abstractapplicationcontext is struct, and defaultresourceloader is the default Implementation.
Filesystemxmlapplicationcontext source code implementation:
Package Org. springframework. context. support; import Org. springframework. beans. beansexception; import Org. springframework. context. applicationcontext; import Org. springframework. core. io. filesystemresource; import Org. springframework. core. io. resource; public class filesystemxmlapplicationcontext extends actxmlapplicationcontext {public filesystemxmlapplicationcontext () {} public filesystemxmlapplicatio Ncontext (applicationcontext parent) {super (parent);} // configlocation is the file path of beandefinition public filesystemxmlapplicationcontext (string configlocation) throws beansexception {This (New String [] {configlocation }, true, null);} // you can specify multiple beandefinition resource paths: Public filesystemxmlapplicationcontext (string... configlocations) throws beansexception {This (configlocations, true, null);} // you can specify multiple beandefinition assets Source Path, and specify your parent container public filesystemxmlapplicationcontext (string [] configlocations, applicationcontext parent) throws beansexception {This (configlocations, true, parent );} public filesystemxmlapplicationcontext (string [] configlocations, Boolean refresh) throws beansexception {This (configlocations, refresh, null);} // call the method of parent class lifecycle and set the resource file defined by beandefinition, complete IOC container Bean Define the resource location // call the refresh () method of the parent class abstractapplicationcontext. This method starts the loading process of beandefinition, public filesystemxmlapplicationcontext (string [] configlocations, Boolean refresh, applicationcontext parent) throws beansexception {super (parent); setconfiglocations (configlocations); If (refresh) {refresh () ;}}// override the defaultresourceloader method of the parent class. Use filesystemresource to obtain the beandefinition located in the file system // getresourceby The path method is called in loadbeandefinition of beandefinitionreader. loadbeandefinition adopts the template mode. Specifically, the subclass completes protected resource getresourcebypath (string path) {If (path! = NULL & path. startswith ("/") {Path = path. substring (1);} return New filesystemresource (PATH );}}
We can see that the constructor implements the configuration processing operation, and then calls the refresh method to start IOC container initialization. This refresh method is defined in the abstractapplicationcontext class, it is a very important method and an important entry for analyzing the container initialization process.
Call relationship of getresourcebypath
Next, let's take a look at the call relationship between the refresh method and the getresourcebypath method:
The entire beandefinition resource locating process can be clearly seen. It was initially triggered by the refresh method, and the refresh call was started in the filesystemxmlapplicationcontext constructor. If you follow the source code to check the refresh method, you will find that the refresh method seems to be a general switch. Many other methods are called within the method to complete IOC initialization. The obtainfreshbeanfactory method exists, the obtainfreshbeanfactory calls the refreshbeanfactory method in the abstractrefreshableapplicationcontext class, which calls loadbeandefinitions to load beandefinition. The following describes the implementation of the refreshbeanfactory method.
Source code for resource locating
From the above analysis, we can see that the refresh method of the abstractapplicationcontext class is the entry for IOC container initialization. The refresh method calls many other methods. In fact, there are actually obtainfreshbeanfactory methods, the obtainfreshbeanfactory calls the refreshbeanfactory method in the abstractrefreshableapplicationcontext class. We will analyze the refreshbeanfactory method.
Refreshbeanfactory method in the abstractrefreshableapplicationcontext class:
Protected final void refreshbeanfactory () throws beansexception {// If beanfactory has been created, destroy and disable the beanfactoryif (hasbeanfactory () {destroybeans (); closebeanfactory ();} try {// create and hold the defaultlistablebeanfactory instance, and call the loadbeandefinitions method to load beandefinition information defaultlistablebeanfactory beanfactory = createbeanfactory (); beanfactory. setserializationid (GETID (); customizebeanfactory (beanfactory); loadbeandefinitions (beanfactory); synchronized (this. beanfactorymonitor) {This. beanfactory = beanfactory;} catch (ioexception ex) {Throw new applicationcontextexception ("I/O error parsing bean Definition source for" + getdisplayname (), Ex );}} // create a defaactlistablebeanfactory instance. for the implementation of the destroy method, see the source code of the abstractapplicationcontext class. It generates the protelistlistablebeanfactory parent container protected defaultlistablebeanfactory () based on the existing parent IOC container information () {return New defaultlistablebeanfactory (getinternalparentbeanfactory ());}
In this method, the createbeanfactory method is called to construct and hold an IOC container for applicationcontext. This IOC container is the defaultlistablebeanfactory mentioned above, and it starts loadbeandefinitions to load beandefinition, this process is very similar to the process of using the IOC container (defaultlistablebeanfactory combined with xmlbeandefinitionreader) programmatically.
Next, enter the loadbeandefinitions method. This method is an abstract method in abstractapplicationcontext. The specific implementation is in the abstractxmlapplicationcontext class.
The loadbeandefinitions method of abstractxmlapplicationcontext:
Protected void loadbeandefinitions (defaultlistablebeanfactory beanfactory) throws beansexception, ioexception {// use the beanfactory you just created to create a new xmlbeandefinitionreader. xmlbeandefinitionreader beandefinitionreader = new xmlbeandefinitionreader (beanfactory); // configure xmlbeandefinitionreader. beandefinitionreader. setenvironment (this. getenvironment (); beandefinitionreader. setresourceloader (this); beandefinitionreade R. setentityresolver (new handler (this); // initialize xmlbeandefinitionreader and then load iterator (beandefinitionreader); loadbeandefinitions (beandefinitionreader);} // The actual loading of javasvoid loadbeandefinitions) throws beansexception, ioexception {resource [] configresources = getconfigresources (); If (configresources! = NULL) {reader. loadbeandefinitions (configresources);} string [] configlocations = getconfiglocations (); If (configlocations! = NULL) {reader. loadbeandefinitions (configlocations );}}
The above Code shows that the loadbeandefinitions method first creates an xmlbeandefinitionreader instance and executes the loadbeandefinitions method of the xmlbeandefinitionreader after configuration and initialization. This is the place where beandefinition is loaded, the execution process of this program enters xmlbeandefinitionreader.
Let's take a look at how it works.
Xmlbeandefinitionreader's loadbeandefinitions method:
Public int loadbeandefinitions (string... locations) throws beandefinitionstoreexception {int counter = 0; For (string location: locations) {counter + = loadbeandefinitions (location);} return counter;} public int loadbeandefinitions (string location) throws beandefinitionstoreexception {return loadbeandefinitions (location, null);} public int loadbeandefinitions (string location, set <resource> actualresour CES) throws beandefinitionstoreexception {// obtain resourceloader. Here defaultresourceloader is used. abstractapplicationcontext inherits resourceresourceloader = getresourceloader (); If (resourceloader = NULL) {Throw new beandefinitionstoreexception ("cannot import bean definitions from location [" + location + "]: No resourceloader available");} // parse the path mode of a resource, obtain the required resource set. Some resource sets point to our defined beandefinition information, which can be multiple files if (resourceloader instanceof resourcepatternresolver) {// call the defaultresourceloader's getresources method to locate the specific resource. Try {resource [] resources = (resourcepatternresolver) resourceloader ). getresources (location); int loadcount = loadbeandefinitions (resources); If (actualresources! = NULL) {for (resource Resource: Resources) {actualresources. add (Resource) ;}return loadcount;} catch (ioexception ex) {Throw new beandefinitionstoreexception ("cocould not resolve bean definition resource pattern [" + location + "]", ex) ;}} else {// call the defaultresourceloader's getresource method to locate the specific resource. resource resource = resourceloader. getresource (location); int loadcount = loadbeandefinitions (Resour CE); If (actualresources! = NULL) {actualresources. Add (Resource) ;}return loadcount ;}}
From the code above, we can see that multiple resource location operators will be located and loaded one by one. In addition, for filesystemxmlapplicationcontext, it will enter the else flow in the loadbeandefinitions method, and the getresource method of resourceloader will be called directly here, that is, the default implementation class defaultresourceloader's getresource method.
The getresource method of defaultresourceloader:
// The specific process of obtaining a resource is defined in the public resource getresource (string location) {// process resourceif (location with the classpath identifier in defaultresourceloader. startswith (classpath_url_prefix) {return New classpathresource (location. substring (classpath_url_prefix.length (), getclassloader ();} else {try {// process URL url = new URL (location) as the resource for URL locating ); return new urlresource (URL);} catch (malformedurlexception ex) {// not the location identified by the URL. Assign the resource locating task to getresourcebypath. // This is a protected method, the default implementation is to get a classpathcontextresource, which is often used to overwrite the quilt class. return getresourcebypath (location );}}}
In the previous source code analysis, the getresourcebypath method is implemented by the filesystemxmlapplicationcontext subclass of defaultresourceloader. This method returns a filesystemresource object. Through this filesystemresource object, spring can locate beandefinition.
After analysis, the location of the resource in the IOC container filesystemxmlapplicationcontext is clear. If it is another type of applicationcontext, other types of resources, such as classpathresource and servletcontextresource, will be generated accordingly.