XmlMapperBuilder that parses mapper files

XmlMapperBuilder is an implementation of BaseBuilder, his role is mainly through the analysis of Mybatis mapper file to complete the creation and initialization of mapper objects.

Mapper file refers to the XML file used to configure the Mapper object of Mybatis mapper.

Such as: Mapper XML:

<mapper namespace="org.apache.learning.typehandler.Mapper">.</mapper>
Copy the code

And Mapper. Java:

package org.apache.learning.typehandler;

public interface Mapper {... }Copy the code

Before we get into the specifics of XmlMapperBuilder parsing, we need to familiarize ourselves with the definition of the Mapper file.

The root element of Mybatis mapper file is mapper, which has a mandatory namespace attribute. Normally, the value of namespace attribute is the fully qualified name defined by the mapper interface corresponding to the current mapper file.

The namespace value defined by the namespace attribute should be unique in the entire Mybatis. Through namespace, Mybatis logically isolates data, ensures that data between different Mapper does not pollute each other, and also provides the ability to reference data configuration across namespaces.

XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream/*XML file inputStream */, configuration/*Mybatis user global configuration */, Url address * / / * resource configuration files, configuration, getSqlFragments existing XML code block () / * * /);Copy the code

For XmlMapperBuilder constructor parameters, the only thing we are not familiar with the configuration should be the getSqlFragments (), Configuration# sqlFragments that store blocks of code is a set of mapping, We’ll talk about that in the next analysis.

The XmlMapperBuilder generates an instance of the XPathParser during construction.

The XPathParser, as mentioned earlier, uses SAX to parse out the DOM tree of the XML corresponding to the input stream and puts it into an XPathParser object.

public XMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
    this(new XPathParser(inputStream, true, the configuration getVariables (), new XMLMapperEntityResolver ()) / * build an XPath parser * /, Configuration,/*Mybatis configuration */ resource/* resource path */, sqlFragments/* existing Sql code blocks */); }Copy the code

It then calls its own other constructors to complete the initialization of the entire XmlMapperBuilder object:

private XMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) { super(configuration); this.builderAssistant = new MapperBuilderAssistant(configuration, resource); /* create Mapper */ this.parser = parser; this.sqlFragments = sqlFragments; this.resource = resource; }Copy the code

MapperBuilderAssistant is a utility assistant used to parse mapper files. It has separate responsibilities from the XmlMapperBuilder object. Most of the data parsed by the XmlMapperBuilder object is passed to the MapperBuilderAssistant object for use.

The XmlMapperBuilder object parses the Mapper file, and the MapperBuilderAssistant object loads and processes the parsed data.

So to some extent the XmlMapperBuilder object is focused on parsing mapper files to get data, and the MapperBuilderAssistant object is focused on interacting with the Mybatis container.

After constructing the XmlMapperBuilder, Mybatis calls the parse() method of XmlMapperBuilder to parse the mapper file.

/* Parse the XML file */ mapperparser.parse ();Copy the code

In the parse() method, the isResourceLoaded(String Resource) method of the Configuration object is first called to check whether the specified resource has been processed. If not, the file is parsed completely.

The Set

loadedResources property of the Configuration object is used to maintain the collection of all loadedResources. The main purpose is to prevent repeated parsing of mapper files.

If the specified mappe file has not been processed before, Mybatis will use the XPathParser to parse all contents of the mapper root element of the mapper file into XNode object entities. We pass it to the configurationElement() method to parse the XNode object and register the parsed data in the Configuration object for use.

/** * MapperXml file parsing method */ public voidparse() {
    if(! Configuration. IsResourceLoaded (resource)) {/ / configuration file to load for the first time will perform complete parsing operations / / read and configure MapperXml file content core logic configurationElement(parser.evalNode("/mapper")); / / record loaded the current configuration. The configuration file addLoadedResource (resource); // Bind the DAO operation interface to the current configurationbindMapperForNamespace(); } // Parse an unfinished ResultMap parsePendingResultMaps(); // Resolve unresolved cache references parsePendingCacheRefs(); ParsePendingStatements (); parsePendingStatements(); }Copy the code

Once the Mapper object has been configured, the bindMapperForNamespace() method attempts to associate these configurations with a specific Mapper object.

/** * bind Mapper to namespace */ private voidbindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if(namespace ! = null) { Class<? > boundType = null; BoundType = Resources. ClassForName (namespace); boundType = Resources. } catch (ClassNotFoundException e) { //ignore, boundtype is not required
        }
        if(boundType ! = null) {if(! Configuration.hasmapper (boundType)) {// Spring may not know the real resource name so weset a flag
                // to prevent loading again this resource from the mapper interface
                // look at MapperAnnotationBuilder#loadXmlResourceloadXmlResource/ / registered loaded collection of resources configuration, addLoadedResource ("namespace:"+ namespace); AddMapper (boundType); // Register the DAO operation interface configuration.addMapper(boundType); }}}}Copy the code

If the specified Mapper object has not been resolved, the addMapper() method of Configuration is called to initialize the Mapper object according to the type definition of the Mapper object.

BindMapperForNamespace () :

@startuml hide footbox participant "XMLMapperBuilder" as x participant "MapperBuilderAssistant" as m participant "Resources" as r participant "Configuration" as c [-> x : BindMapperForNamespace ()\n Activate X x -> m ++:getCurrentNamespace() returns the namespace Currently configured namespace opt the configured namespace x -> r++: X -> c++ :hasMapper() x -> c++ :hasMapper() Return check whether the Mapper is loaded. Opt Check whether the Mapper is loaded. Return x->c++:addMapper() \n addMapper interface end end [< -x :addMapper interface end end [< -x :addMapper interface end end [< -x :addMapper interface Finish parsing a Mapper file @endUMLCopy the code

parse()
parsePendingResultMaps()
parsePendingCacheRefs()
parsePendingCacheRefs()
Mapper

The overall flow of the Parse method is as follows:

@startuml hide footbox participant XMLMapperBuilder as x participant Configuration as c [-> x : Parse () \n activate x x->c++:isResourceLoaded() \n whether the current resource configuration file is loaded return opt the resource configuration file is not loaded X ->x++:configurationElement() \n :configurationElement(); return x->c ++:addLoadedResource() \n :addLoadedResource() Return end x->x++:parsePendingResultMaps()\n parsePendingResultMaps()\n Parse an unfinished ResultMap Return x->x++:parsePendingCacheRefs()\n parsePendingStatements()\n parsePendingStatements()\n parsePendingStatements()\n parsePendingStatements return [< -x: Finish parsing a Mapper file @endUMLCopy the code

XmlMapperBuilder
Mapper

Follow me and learn more together