Beauty of Mybatis source code: 2.3. Parse Properties sub element and initialize property configuration

Resolve the Properties sub element and initialize the property configuration

> Click to learn the configuration method of the properties element

After the basic environment of Mybatis for parsing XML is ready, we can finally usher in the first real configuration file parsing operation.

propertiesElement(root.evalNode("properties"));

The propertiesElement method reads the configuration of the properties element in the mybatis global configuration file and converts it to a properties object.

The properties element is one of the 11 child nodes in the configuration element. Its DTD is defined as follows:

<!--ELEMENT properties (property*)-->
<!--ATTLIST properties
resource CDATA #IMPLIED
url CDATA #IMPLIED
-->

It allows multiple property child nodes and can also configure the resource and url properties, but the resource and url properties cannot exist at the same time, The definition of the property sub node is as follows:

<!--ELEMENT property EMPTY-->
<!--ATTLIST property
name CDATA #REQUIRED
value CDATA #REQUIRED
-->

The property element is made up of name and value, so it can be parsed into a Properties object. In the following specific parsing process, we will see that Mybatis provides corresponding parsing operations for these three different configurations.

/**
  * Resolving Properties Tags
  *
  * @param context Properties node
  * @throws Exception abnormal
  */
 private void propertiesElement(XNode context) throws Exception {
     // The user has configured the properties node
     if (context != null) {
         // Get the name and value values of the Property node under Properties, and convert the Properties Property
         Properties defaults = context.getChildrenAsProperties();
         // Get referenced resources
         String resource = context.getStringAttribute("resource");
         String url = context.getStringAttribute("url");

         if (resource != null &amp;&amp; url != null) {
             throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
         }

         if (resource != null) {
             // Load *. Properties resource profile
             defaults.putAll(Resources.getResourceAsProperties(resource));
         } else if (url != null) {
             // Load *. Properties resource profile
             defaults.putAll(Resources.getUrlAsProperties(url));
         }
         // Get the property configuration passed in by user code
         Properties vars = configuration.getVariables();
         if (vars != null) {
             // Merge property configuration
             defaults.putAll(vars);
         }
         // Refresh the variable references in the parser for subsequent parsing
         parser.setVariables(defaults);
         // Sync to Mybatis settings
         configuration.setVariables(defaults);
     }
 }

First, get all the property sub nodes under the properties object, and generate a property instance accordingly.

// Get the name and value values of the Property node under Properties, and convert the Properties Property
Properties defaults = context.getChildrenAsProperties();

among context.getChildrenAsProperties() code is as follows:

/**
 * Gets all the child nodes under the specified package element, and after reading their name and value Properties, converts them to Properties objects.
 *
 */
public Properties getChildrenAsProperties() {
    Properties properties = new Properties();
    for (XNode child : getChildren()) {
        // Read name and value properties
        String name = child.getStringAttribute("name");
        String value = child.getStringAttribute("value");
        if (name != null &amp;&amp; value != null) {
            // If there are both name and value attributes, save them
            properties.setProperty(name, value);
        }
    }
    return properties;
}

Its function is to get all the element nodes under the current node. After reading their name and value Properties, they are converted into Properties objects. The getChildren() method in the code is used to filter out the effective set of element nodes:

public List<xnode> getChildren() {
     List<xnode> children = new ArrayList&lt;&gt;();
     // Get all child nodes
     NodeList nodeList = node.getChildNodes();
     if (nodeList != null) {
         for (int i = 0, n = nodeList.getLength(); i &lt; n; i++) {
             Node node = nodeList.item(i);
             if (node.getNodeType() == Node.ELEMENT_NODE) {
                 // Filter out child nodes
                 children.add(new XNode(xpathParser, node, variables));
             }
         }
     }
     return children;
 }

After processing the property sub node of properties, mybatis will obtain the resource and url properties of properties respectively.

mybatis first verifies that both cannot exist at the same time.

if (resource != null &amp;&amp; url != null) {
       throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
   }

Then load the corresponding resource file according to the value of the resource/url property and convert its content into a property object and save it to the property object obtained in the previous step.

if (resource != null) {
    // Load *. Properties resource profile
    defaults.putAll(Resources.getResourceAsProperties(resource));
} else if (url != null) {
    // Load *. Properties resource profile
    defaults.putAll(Resources.getUrlAsProperties(url));
}

Then take out the existing variables in the Configuration, which are passed in by the user code, and save them to the Properties object as well.

// Get the property configuration passed in by user code
Properties vars = configuration.getVariables();
if (vars != null) {
   // Merge property configuration
   defaults.putAll(vars);
}

In fact, it is not difficult to understand the attribute configuration of Mybatis through the loading order of appeals. The effective priority is from high to low: Parameters set at startup - > configuration pointed to by the url/resource property of properties in mybatis main configuration file - > property configuration of properties in mybatis main configuration file.

At this stage, all the global attribute configurations have been loaded. The next step is to use these attributes.

First, update the global variable reference in xpathParser, and then use it when parsing the file.

// Refresh the variable references in the parser for subsequent parsing
parser.setVariables(defaults);

Then save these global properties to Configuration, and the parsing operation of the properties element is completed.

// Sync to Mybatis settings
configuration.setVariables(defaults);

Add:

In the above step of loading the corresponding resource file according to the value of the resource/url property and converting its content into a Properties object, we have involved a Resources object, which is a tool class used by mybatis to simplify resource access.

There is a ClassLoaderWrapper type attribute in the Resources object, which is the wrapper class of ClassLoader defined in mybatis. It holds multiple different ClassLoader implementations internally. When users try to get Resources through ClassLoaderWrapper, changing the wrapper class will try to use multiple classloaders to load Resources.

The implementation of Resources and ClassLoaderWrapper are relatively simple. If you are interested, you can check the source code yourself, and we will not go into details here.

Pay attention to me and learn more together

</xnode></xnode>

Tags: Programming Mybatis Attribute xml

Posted on Fri, 05 Jun 2020 02:04:05 -0400 by AndyEarley