Basic Concepts
Beandefinitionreader , the function of this class is to read the contents of the Spring configuration file and convert it into a data structure inside the IOC container, and the container's data structure is beandefinition.
The functionality of this class can be summed up in two steps:
Here's an interface definition:
Public interface beandefinitionreader {Beandefinitionregistry GetRegistry (); Resourceloader Getresourceloader (); ClassLoader Getbeanclassloader (); Beannamegenerator Getbeannamegenerator ();//Key---responsible for beandefinition loading, reading resrouce content, through Beandefinitiondocumentreader to parse it into Beandefinition intLoadbeandefinitions (Resource Resource)throwsBeandefinitionstoreexception;intLoadbeandefinitions (Resource ... resources)throwsBeandefinitionstoreexception;//Key---responsible for beandefinition resource positioning, using Resourceloder to obtain resrouce instance according to path intLoadbeandefinitions (String location)throwsBeandefinitionstoreexception;intLoadbeandefinitions (String ... locations)throwsBeandefinitionstoreexception;}
Then look at its inheritance:
Source Analysis
First, the Spring Ioc container starts from start to call the Beandefinitionreader process.
Note: Since the XML file is used as the Spring configuration file by default, Xmlbeandefinitionreader is called to handle it.
Here's a look at Xmlbeandefinitionreader's workflow:
Public int loadbeandefinitions(String location)throwsbeandefinitionstoreexception {returnLoadbeandefinitions (Location,NULL);} Public int loadbeandefinitions(String location, set<resource> actualresources)throwsbeandefinitionstoreexception {//Step one: Get the resource loaderResourceloader Resourceloader = Getresourceloader ();//Step two: Check the resource loader (to determine if it is empty) if(Resourceloader = =NULL) {//Throw an exception ...}//Step two: Verify the resource loader (determine if the Resourcepatternresolver interface is implemented) if(ResourceloaderinstanceofResourcepatternresolver) {//Resource pattern matching available. Try{//Step three: Resource orientation of key---Beandefinitionresource[] Resources = ((Resourcepatternresolver) resourceloader). getresources (location);//Step four: Loading of key---Beandefinition intLoadcount = loadbeandefinitions (resources);if(Actualresources! =NULL) { for(Resource resource:resources) {Actualresources.add (Resource); } }//Log Output ... returnLoadcount; }Catch(IOException ex) {//Throw an exception ...} }Else{Resource Resource = resourceloader.getresource (location);intLoadcount = loadbeandefinitions (Resource);if(Actualresources! =NULL) {Actualresources.add (Resource); }//Log Output ... returnLoadcount; }}
Observing the code, the Beandefinitionreader workflow can be divided into four steps:
Once again, the Beandefinitionreader function is verified by code, and then the next two steps are explored in detail.
1.BeanDefinition Resource Positioning
Resource positioning is the process of getting an Resource instance object. The beandefinitionreader itself does not have this function, but instead obtains the Resource instance through resourceloader .
The above mentioned Beandefinitionreader will be to determine whether Resourceloader implement Resourcepatternresolver interface, the essence is to determine whether the Resourceloader support Access multiple resources at the same time .
- If multiple resources are supported concurrently, the Resrouce array is returned.
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
First, let's look at the inheritance relationship of the Resourcepatternresolver interface:
Here Xmlbeandefinitionreader will default to calling the Getresources method of the parent class Abstractapplicationcontext:
publicgetResourcesthrows IOException { // 此时 resourcePatternResolver 为 ServletContextResourcePatternResolver returnthis.resourcePatternResolver.getResources(locationPattern);}
The servletcontextresourcepatternresolver will then call the parent class Pathmatchingresourcepatternresolver by default. Getresources method.
Pathmatchingresourcepatternresolver in the introduction of Resourceloader has been explored here is not detailed.
The entire invocation process is as follows:
- If simultaneous access to multiple resources is not supported, a single Resource object is returned:
Resource resource = resourceLoader.getResource(location);
The whole resource positioning process is relatively simple, which is closely related to the two classes of Resource and Resourceloader. Spring does this by abstracting the different types of resources into the Resrouce interface, and then by Resourceloader, so that spring is only coupled to the Resource interface and no longer cares about what type of resource access is used at the bottom.
2.BeanDefinition Loading
Loading, refers to the process of reading Resource content and loading it as a doucument.
Here's a look at the specific process:
- Get Resource, add encoded information, and turn it into encodedresource
publicintloadBeanDefinitionsthrows BeanDefinitionStoreException { // 将 resource 包裹在 EncodedResource 中,其实例化过程会为 Resource 添加编码信息,这里默认编码信息为 null return loadBeanDefinitions(new EncodedResource(resource));}
- Ready to start reading the content by getting the input stream of the Resource and adding it into the InputSource
Public int loadbeandefinitions(Encodedresource Encodedresource)throwsbeandefinitionstoreexception {assert.notnull (Encodedresource,"Encodedresource must not being null");//Log Output ... //Get resources that have been loadedSet<encodedresource> currentresources = This. Resourcescurrentlybeingloaded.get ();//If no loaded resources exist, create a new HashSet to load after storage if(Currentresources = =NULL) {currentresources =NewHashset<encodedresource> (4); This. Resourcescurrentlybeingloaded.set (Currentresources); }//Add the current resource into the HashSet if(!currentresources.add (Encodedresource)) {//If the current resource already exists, throw an exception ...}Try{//All types of Resource can be converted into stream operationsInputStream InputStream = Encodedresource.getresource (). getInputStream ();Try{//Add stream to InputSource to prepare for SAX parsingInputSource InputSource =NewInputSource (InputStream);//Set encoding if(encodedresource.getencoding ()! =NULL) {inputsource.setencoding (encodedresource.getencoding ()); }//Key--Start the real beandefinitions loading process returnDoloadbeandefinitions (InputSource, Encodedresource.getresource ()); }finally{Inputstream.close (); } }Catch(IOException ex) {//Throw an exception ...}finally{//Last exception to the currently loaded resourceCurrentresources.remove (Encodedresource);//resource Set if empty, remove together if(Currentresources.isempty ()) { This. Resourcescurrentlybeingloaded.remove (); } }}
- Because Spring uses an XML configuration file here, the document object is obtained using SAX parsing
protected int doloadbeandefinitions(InputSource InputSource, Resource Resource)throwsbeandefinitionstoreexception {Try{//Using SAX parsing to get the document object of an XML fileDocument doc = doloaddocument (InputSource, Resource);//Key---parse and register beandefinitions returnRegisterbeandefinitions (Doc, Resource); }Catch(Beandefinitionstoreexception ex) {//Throw an exception ...}Catch(Saxparseexception ex) {//Throw an exception ...}Catch(Saxexception ex) {//Throw an exception ...}Catch(Parserconfigurationexception ex) {//Throw an exception ...}Catch(IOException ex) {//Throw an exception ...}Catch(Throwable ex) {//Throw an exception ...}}
This concludes with a simple overview of the entire onboarding process:
Get the Resource and add the encoded information and turn it into Encodedresource.
Get Resource input stream, add into InputSource, and SAX parse to prepare.
Obtain InputSource, use SAX parse to get Document object, complete loading.
3.BeanDefinition Parsing and registration
In the previous step, Xmlbeandefinitionreader has made the XML Document object and completed the onboarding process. The next thing to do is to beandefinition the parsing and registration process. This feature is specifically implemented by Beandefinitiondocumentreader .
publicintregisterBeanDefinitionsthrows BeanDefinitionStoreException { // 利用 documentReader 对配置文件的内容进行解析 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); // 取得已经注册 BeanDefinition int countBefore = getRegistry().getBeanDefinitionCount(); // 关键 -> 注册 BeanDefinition (包含解析过程) documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore;}
Summary
After analyzing the specific work flow of beandefinitionreader, finally, a simple diagram is presented:
Spring Source Inquiry-Beandefinitionreader