Basic concepts
Beandefinitionreader, the function of this interface is to load the Bean.
In Spring, beans are generally defined in a configuration file. The path that is configured is defined in Web. Xml. So the steps to load the Bean are basically:
Load a resource, load a profile (Resource) from a configuration file path (location)
Parse the resource to get the Bean by parsing the contents of the configuration file.
Here's an interface definition:
Publicinterface beandefinitionreader {BeanDefinitionRegistry GetRegistry (); Resourceloader Getresourceloader (); ClassLoader Getbeanclassloader (); Beannamegenerator Getbeannamegenerator (); //through Resource load Bean int loadbeandefinitions (Resource Resource) throws beandefinitionstoreexception; int loadbeandefinitions (Resource ... resources) throws Beandefinitionstoreexception; //load resources through location int loadbeandefinitions (String location) Span class= "Hljs-keyword" >throws beandefinitionstoreexception; int loadbeandefinitions (String ... locations) throws beandefinitionstoreexception;}
The specific inheritance relationship is as follows:
Process Analysis
First, the Spring Ioc container starts from start to call Beandefinitionreader to load the Bean as follows:
Note: Because the XML file is used here as a Spring configuration file, Xmlbeandefinitionreader is called by default to handle it.
1. Loading beans via Beanfactory
Within the Spring container (ApplicationContext) There is an internal container (beanfactory) responsible for the creation and management of the Bean.
After creating the Beanfactory, the next step is to load the Bean. It is the responsibility of the Loadbeandefinitions method.
ProtectedvoidLoadbeandefinitions (Defaultlistablebeanfactory beanfactory)Throws Beansexception, IOException {1. Create Beandefinitionreader Xmlbeandefinitionreader Beandefinitionreader =New Xmlbeandefinitionreader (beanfactory);2. Setting the Beandefinitionreader Properties2.1. Set the environment, i.e. the environment, in accordance with the environment of the container Beandefinitionreader.setenvironment (Getenvironment ());//2.2. Set Resourceloader, which is the resource loader, because the container implements the interface, the function of loading the resources beandefinitionreader.setresourceloader (this); //2.3. Set Entityresolver, the entity resolver, which is used to parse the resource content loaded by the resource loader beandefinitionreader.setentityresolver (new Resourceentityresolver (this)); //3. Initialize Beandefinitionreader, empty method Initbeandefinitionreader (Beandefinitionreader); //4. Load Bean loadbeandefinitions (beandefinitionreader) via Beandefinitionreader;} //Constructor public Xmlbeandefinitionreader (Beandefinitionregistry registry) { //internal beanfactory is treated as Bean registrar super (registry);}
Observing the code, the main purpose of the method is to create a beandefinitionreader and to load the Bean. The process is as follows:
- Create Beandefinitionreader
- Setting the related properties of Beandefinitionreader
- Initialize Beandefinitionreader
- Loading beans through Beandefinitionreader
2. Loading beans via Beandefinitionreader
After the Beandefinitionreader is created, it is necessary to load the Bean with the following procedure:
// 通过 BeanDefinitionReader 加载 Bean protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { // 取得 Spring 容器的所有配置文件 String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { // 调用 BeanDefinitionReader 加载 Bean reader.loadBeanDefinitions(configLocation); } }}
3. Loading beans via location
The responsibility for the loaded Bean is given to Beandefinitionreader, and the following is a look at the Loadbeandefinitions method of the class.
PublicIntLoadbeandefinitions (String location)Throws Beandefinitionstoreexception {return Loadbeandefinitions (location,NULL);}PublicIntLoadbeandefinitions (String location, set<resource> actualresources)Throws Beandefinitionstoreexception {1. Obtain the resource loader, which is the container itself resourceloader Resourceloader = Getresourceloader ();if (Resourceloader = =NULL) {Throw exception ...}Determine the resource loader typeif (ResourceloaderInstanceof Resourcepatternresolver) {Indicates that the Resourceloader can load multiple resources based on a pathtry {2. Load resource resource[] resources = ((Resourcepatternresolver) resourceloader). getresources (location);3. Loading beans via Resourceint Loadcount = loadbeandefinitions (resources); if (actualresources! = null) {for (Resource resource:resources) {Actualresources.add (Resource);} } //omit code ... return Loadcount;} catch (IOException ex) {//throws an exception ...}} else {//means Resourceloader can only load one resource Resource Resource = Resourceloader.getresource (location); int loadcount = loadbeandefinitions (Resource); if (actualresources! = null) {Actualresources.add (Resource);} //omit code ... return loadcount;}
Observation code, the workflow of this method can be divided into four steps:
4. Loading beans via Resource
After the resource (Resource) is obtained, the method encapsulates it and makes it a Encodedresource object.
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { // EncodedResource 表示编码类型的资源 return loadBeanDefinitions(new EncodedResource(resource));}// 构造函数public EncodedResource(Resource resource, String encoding) { // 封装资源,并带上编码类型 this(resource, encoding, null);}
5. Loading beans via Encodedresource
PublicIntLoadbeandefinitions (Encodedresource Encodedresource)Throws Beandefinitionstoreexception {Omit code ...1. Obtain a collection of [loaded resources] for the presence of loaded resources. Empty, it is created. Set<encodedresource> currentresources =This.resourcesCurrentlyBeingLoaded.get ();if (currentresources = =NULL) {currentresources =New Hashset<encodedresource> (4);This.resourcesCurrentlyBeingLoaded.set (currentresources); }2. Add the current resource to the collectionif (!currentresources.add (Encodedresource)) {Throw exception ...}try {3. Convert the resource to stream inputstream InputStream = Encodedresource.getresource (). getInputStream ();try {//5. Create InputSource via stream and set encoding inputsource InputSource = new InputSource (InputStream); if (encodedresource.getencoding ()! = null) { Inputsource.setencoding (Encodedresource.getencoding ()); } //6. InputSource load Bean return doloadbeandefinitions ( InputSource, Encodedresource.getresource ()); }finally {inputstream.close ();}} catch (IOException ex) {//throws an exception ...} finally {//remove the resources that have been resolved currentresources.remove ( Encodedresource); //collection is empty, then delete if (Currentresources.isempty ()) {this.resourcescurrentlybeingloaded.remove (); } }}
- Get the loaded resource collection
- To add the current resource to the collection
- Convert a resource into a stream
- Create a inputsource with a stream and set the encoding
- Loading beans through InputSource
6. Loading beans via InputSource
The reason for converting Resource to InputSource is to prepare for SAX parsing.
ProtectedIntDoloadbeandefinitions (InputSource InputSource, Resource Resource)Throws Beandefinitionstoreexception {try {1. Parse XML file doc = doloaddocument (InputSource, Resource);2. Registering beansReturn Registerbeandefinitions (Doc, Resource); }catch (Beandefinitionstoreexception ex) {Throw exception ...}catch (Saxparseexception ex) {//throws an exception ...} catch (Saxexception ex) {//throws an exception ...} catch (Parserconfigurationexception ex) {//throws an exception ...} catch (IOException ex) {//throws an exception ...} catch (Throwable ex) {//throws an exception ...}} //parse the XML file and return the Document object. protected Document doloaddocument (InputSource InputSource, Resource Resource) throws Exception {return this.documentloader.loaddocument (InputSource, Getentityresolver (), This.errorhandler, Getvalidationmodeforresource (Resource), Isnamespaceaware ());}
3.Bean Registration
In the previous step, Xmlbeandefinitionreader has obtained the Document object of XML, and completed the parsing process of the resource.
The next step is the Bean registration process.
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { // 利用 documentReader 对配置文件的内容进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // 取得已经注册 BeanDefinition int countBefore = getRegistry().getBeanDefinitionCount(); // 关键 -> 注册 BeanDefinition (包含解析过程) documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}
Summarize
After analyzing the specific work flow of beandefinitionreader, finally, a simple diagram is presented:
07.Spring Bean Load-beandefinitionreader