The article directories

  • One, foreword
  • What does MyBatis initialization do?
    • 2.1 The initialization process of Mybatis is the process of loading the configuration information required by the runtime of Mybatis
    • 2.2 What is the configuration information of Mybatis?
    • 2.3 Mybatis -config. XML and Configuration class
    • 2.4 There are two ways to initialize MyBatis/two ways to bootstrap MyBatis
  • MyBatis creates a Configuration object based on the XML Configuration file
    • 3.1 Locate the key sentence of Mybatis initialization
    • 3.2 Basic initialization process of MyBatis
      • 3.2.1 Mybatis initialization sequence diagram (no specific logic for Parse ())
      • 3.2.2 Four steps to initialize Mybatis
      • 3.2.3 Corresponding codes for four steps of Mybatis initialization
      • 3.2.4 Interfaces and Classes involved in Mybatis initialization
    • 3.3 Important Method: Parse () internally creates a Configuration object
      • 3.3.1 First step, from XMLConfigBuilder to XPathParser
      • 3.3.2 Step 2 Resolve the Configuration node
      • 3.3.3 In the third step, set the parsed value to the Configuration object
      • 3.3.4 Step 4: Return the Configuration object
    • 3.4 Summary: Sequence diagram refinement of the basic process of MyBatis initialization (with parse() logic)
    • 3.5 Summary: Manually load the XML Configuration file. Create a Configuration object. After initialization, create and use the SqlSessionFactory object
  • Summary: Design patterns involved in Mybatis initialization
    • 4.1 Application of Builder Mode 1: creation of SqlSessionFactory
    • 4.2 Application in Builder Mode 2: Creating the Environment object for database connection
  • Five, the summary

One, foreword

Any framework requires a series of initializations before use, and MyBatis is no exception.

What does MyBatis initialization do?

2.1 The initialization process of Mybatis is the process of loading the configuration information required by the runtime of Mybatis

The initialization of any framework is nothing more than loading the configuration information required by its runtime, so is Mybatis. The initialization process of Mybatis is the process of loading the configuration information required by its runtime.

The initialization process of Spring is the process of loading the configuration information required by its runtime, and the initialization process of Mybatis is the process of loading the configuration information required by its runtime.

2.2 What is the configuration information of Mybatis?

The configuration information of MyBatis probably contains the following information, and its high-level structure is as follows:

X configuration configuration x properties property x Settings x typeAliases type name x typeHandlers type handler x objectFactory objectFactory x plugins Plugins × environments × environment variables × transactionManager transactionManager × dataSource dataSource × mapperCopy the code

The above configuration information of MyBatis will be configured in the XML configuration file, so, these information is loaded into MyBatis internal, how to maintain MyBatis?

2.3 Mybatis -config. XML and Configuration class

MyBatis took a very straightforward and simple way – using org. Apache. Ibatis. Session. The Configuration object as a container all Configuration information, The Configuration object is organized almost exactly the same as an XML Configuration file (of course, the Configuration object does more than that; it also creates objects for internal use in MyBatis, such as Executors, etc.). As shown below:

MyBatis according to the initialization of the Configuration information, this time users can use MyBatis database operation.

It can be said that the process of initialization of MyBatis is the process of creating a Configuration object.

2.4 There are two ways to initialize MyBatis/two ways to bootstrap MyBatis

Initialization of MyBatis can be done in two ways (MyBatis boot layer: based on XML configuration file + based on Java API) :

Xml-based Configuration file: All the Configuration information of MyBatis is stored in an XML file. MyBatis assembles the Configuration information into an internal Configuration object by loading and storing the XML Configuration file.

Based on Java API: This method does not use XML Configuration files, MyBatis users need to manually create a Configuration object in Java code, and then enter the Configuration parameter set into the Configuration object.

Next, we will take a closer look at how MyBatis builds a Configuration object from a Configuration file and uses it by initializing MyBatis using an XML Configuration file.

MyBatis creates a Configuration object based on the XML Configuration file

3.1 Locate the key sentence of Mybatis initialization

Let’s start with a simple example of how to initialize MyBatis and what it initializes. Look at the following code:

String resource = "mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");
Copy the code

MyBatis use experience of readers will know, the role of the above statement is executed. Com foo bean. BlogMapper. QueryAllBlogInfo defined SQL statements, return a List the result set. In general, the above code goes through three processes: mybatis initialization, SqlSession creation, SQL statement execution and return results.

The function of the above code is to create the SqlSessionFactory object from the mybatis-config. XML configuration file, and then generate the SqlSession, execute the SQL statement. Mybatis initialization occurs in the third sentence:

SqlSessionFactory sqlSessionFactory =
    new SqlSessionFactoryBuilder().build(inputStream);
Copy the code

Now let’s see what happens in the third sentence.

3.2 Basic initialization process of MyBatis

SqlSessionFactoryBuilder generates a Configuration object from the incoming data stream (inputStream above), and then creates a default SqlSessionFactory instance from the Configuration object.

3.2.1 Mybatis initialization sequence diagram (no specific logic for Parse ())

The basic initialization process is shown in the sequence diagram below:

Classes and interfaces involved in this sequence diagram: SqlSessionFactoryBuilder, XMLConfigBuilder, Configuration, XPathParser, XMLMapperEntityResolver (1) SqlSessionFactoryBuilder XMLConfigBuilder is a constructor for a non-abstract class, SqlSessionFactory, that creates the SqlSessionFactory using the Builder design pattern. Use inputStream/ Reader to get the XMLConfigBuilder class object, referred to as Parser, which is used to parse() to get the Configuration object.

The corresponding interpretation of the sequence diagram above is: Build (inputStream,null,null); // Mybatis initializes the first step, calling build(). XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); Parse.parse () =parser.parse(); parser.parse() =parser.parse(); // mybatis initialization step 4, SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

3.2.2 Four steps to initialize Mybatis

As shown in the figure above, myBatis initialization goes through the following simple steps:

  1. Call the build(inputStream) method of the SqlSessionFactoryBuilder object;
  2. SqlSessionFactoryBuilder creates an XMLConfigBuilder object based on inputStream inputStream, etc.
  3. Parse () The underlying parse() gets the Configuration object: SqlSessionFactoryBuilder calls the parse() method of the XMLConfigBuilder object, which returns the Configuration object;
  4. Bulid () The underlying Configuration object gets the DefaultSessionFactory object: SqlSessionFactoryBuilder creates a DefaultSessionFactory object from the Configuration object, which is an implementation class of the SqlSessionFactory interface. All build() returns a return type of SqlSessionFactory; SqlSessionFactoryBuilder returns the DefaultSessionFactory object to the Client for use by the Client.

3.2.3 Corresponding codes for four steps of Mybatis initialization

The code for SqlSessionFactoryBuilder looks like this:

public SqlSessionFactory build(InputStream inputStream) { //1. Call the build(inputStream) method of the SqlSessionFactoryBuilder objectreturnbuild(inputStream, null, null); } public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { try { //2. Create the XMLConfigBuilder object to parse the XML configuration file, XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); //3. Parse the information in the XML Configuration file into a Java object. Configuration config = parser.parse(); //4. Create an SqlSessionFactory object based on the Configuration objectreturn build(config);
    }
    catch (Exception e)
    {
        throw ExceptionFactory.wrapException("Error building SqlSession.", e); } finally { ErrorContext.instance().reset(); try { inputStream.close(); } catch (IOException e) {// Intentionally ignore. Prefer previous error.}}} MyBatis uses the Configuration object internally to create the SqlSessionFactory. Users can also construct the Configuration object through the API. SqlSessionFactory public SqlSessionFactory Build (Configuration config) {return new DefaultSqlSessionFactory(config);
}
Copy the code

3.2.4 Interfaces and Classes involved in Mybatis initialization

In the initialization process above, the following objects are involved:

(1) SqlSessionFactoryBuilder: is a non-abstract class, SqlSessionFactory constructor, used to create SqlSessionFactory, using the Builder design mode

(2) Configuration: is a non-abstract class that can instantiate the object, which is all the MyBatis Configuration information in the mybatis-config. XML file

(3) SqlSessionFactory: SqlSessionFactory class, is an interface, implementation class is DefaultSqlSessionFactory, in the form of Factory to create SqlSession object, using the Factory Factory design mode

(4) XmlConfigParser: Parses the mybatis-config. XML Configuration file into a Configuration object used by SqlSessonFactoryBuilder to create the SqlSessionFactory

3.3 Important Method: Parse () internally creates a Configuration object

Following the basic MyBatis initialization discussion above, when SqlSessionFactoryBuilder executes the build() method, the parse() method of XMLConfigBuilder is called, and the Configuration object is returned. So how does the parse() method process the XML file to generate a Configuration object?

3.3.1 First step, from XMLConfigBuilder to XPathParser

The XMLConfigBuilder converts the XML configuration file information into a Document object, and the XML configuration definition file DTD into an XMLMapperEntityResolver object, and then encapsulates both into an XpathParser object. The purpose of XpathParser is to provide operations to get basic DOM Node information based on Xpath expressions. As shown below:

XML configuration file (mybatis-config.xml + xxxmapper.xml) into a Document object, The XML configuration definition file DTD (Mybatis -3-config. DTD + Mybatis -3-mapper. DTD) is converted into an XMLMapperEntityResolver object, Both are then wrapped into an XpathParser object

The purpose of XpathParser is to provide operations to get basic DOM Node information based on Xpath expressions

3.3.2 Step 2 Resolve the Configuration node

Following this, XMLConfigBuilder calls the parse() method: It takes the Node object from XPathParser and parses the child nodes of this Node: properties, settings, typeAliases,typeHandlers, objectFactory, objectWrapperFactory, plugins, Environments, databaseIdProvider, mappers (10)

    public Configuration parse()
    {
        if (parsed)
        {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        }
        parsed = true; ParseConfiguration (parser.evalnode)"/configuration")); ConfigurationNode = parser.evalNode() configurationNode = parser.evalNode()"/configuration");
        parseConfiguration(configurationNode);
        returnconfiguration; } / * parsing"/configuration"Configuration object */ private void parseConfiguration(XNode root) {try {//1 The properties node propertiesElement(root.evalNode("properties")); 
      //issue #117 read properties first//2. Handle typeAliases typeAliasesElement(root.evalNode("typeAliases")); //3. PluginElement (root.evalNode())"plugins")); //4. Handle objectFactory objectFactoryElement(root.evalNode("objectFactory"));
      //5.objectWrapperFactory
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      //6.settings
      settingsElement(root.evalNode("settings")); //7. Handle Environments environmentsElement(root.evalNode("environments")); 
      // read it after objectFactory and objectWrapperFactory issue # 631
      //8.database
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      //9. typeHandlers
      typeHandlerElement(root.evalNode("typeHandlers"));
      //10 mappers
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "+ e, e); }}Copy the code

Note: Another very important point in the above code is the method mapperElements(root.evalNode(” mappers “)) that parses the mapper.xml configuration file we configured, Mapper configuration file can be said to be the core of MyBatis, MyBatis characteristics and concepts are reflected in the configuration and design of Mapper.

3.3.3 In the third step, set the parsed value to the Configuration object

EnvironmentsElement (root.evalNode(” environments “)); environmentsElement(root.evalNode(” environments “)); environmentsElement(root.evalNode(” environments “)); environmentsElement(root.evalNode(” environments “)); To do this, you can parse the information for Environments and set it to a Configuration object:

Note that when envronment is created, if the SqlSessionFactoryBuilder specifies a specific environment (that is, the data source); Return the Environment object of the specified Environment (data source), otherwise return the default Environment object; Private void environmentsElement(XNode Context) throws Exception {MyBatis can connect to multiple data sources */if(context ! = null) {if (environment == null)
        {
            environment = context.getStringAttribute("default");
        }
        for (XNode child : context.getChildren())
        {
            String id = child.getStringAttribute("id");
            if(isSpecifiedEnvironment(id)) { //1. Create a transaction factory TransactionFactory, further child nodes TransactionFactory txFactory = transactionManagerElement (child. EvalNode ("transactionManager"));
                DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource DataSource = dsfactory.getdatasource (); Environment.builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)  .dataSource(dataSource); / / 4. Will create the Envronment Settings to the configuration in the configuration object. The object setEnvironment (environmentBuilder. The build ()); } } } } private boolean isSpecifiedEnvironment(String id) {if (environment == null)
    {
        throw new BuilderException("No environment specified.");
    }
    else if (id == null)
    {
        throw new BuilderException("Environment requires an id attribute.");
    }
    else if (environment.equals(id))
    {
        return true;
    }
    return false;
}
Copy the code

3.3.4 Step 4: Return the Configuration object

public Configuration parse() { if (parsed) { throw new BuilderException("Each XMLConfigBuilder can only be used once.");  } parsed = true; ParseConfiguration (parser.evalnode ("/configuration")); ConfigurationNode = parser.evalNode("/configuration"); // configurationNode = parser.evalNode("/configuration"); parseConfiguration(configurationNode); **return configuration**; // When done, return the Configuration object to the programmer,}Copy the code

3.4 Summary: Sequence diagram refinement of the basic process of MyBatis initialization (with parse() logic)

We refined the sequence diagram of the above basic process of MyBatis initialization.

Classes and interfaces involved in this sequence diagram: SqlSessionFactoryBuilder, XMLConfigBuilder, Configuration, XPathParser, XMLMapperEntityResolver

(1) SqlSessionFactoryBuilder: is a non-abstract class, SqlSessionFactory constructor, used to create SqlSessionFactory, using the Builder design mode

(2) XMLConfigBuilder: Use inputStream/ Reader to get the XMLConfigBuilder class object, referenced as Parser, which is used to parse() to get the Configuration object

(3) Configuration: is a non-abstract class that can instantiate the object, which is all the MyBatis Configuration information in the mybatis-config. XML file

(4) XPathParser:



XMLMapperEntityResolver:



Parse () method first step:XMLConfigBuilderIt converts the XML configuration file information into a Document object, and the XML configuration definition file DTD into an XMLMapperEntityResolver object, and then wraps both into an XpathParser object, The purpose of XpathParser is to provide operations to get basic DOM Node information based on Xpath expressions

SqlSessionFactory: SqlSessionFactory class, is an interface, implementation class is DefaultSqlSessionFactory, create SqlSession object in the form of Factory, using the Factory design pattern

XmlConfigParser: Parses the mybatis-config. XML Configuration file into a Configuration object used by SqlSessonFactoryBuilder to create the SqlSessionFactory

Here’s the explanation: XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); 2.1 2.2 Just create an XMLMapperEntityResolver object; 3.1 3.2 Creating an XPathParser object; 4.1 4.2 Creating a Configuration Object. Parse () builds the configuration object from 5 to 11. Parse () is used to parse the configuration node in mybatis-config. XML. The configuration node in mybatis-config. XML is used to parse the child node. Parse () The first step: From XMLConfigBuilder to XPathParser // Parse () The second step: Parse () Step 3: Set the parsed value to the Configuration object // Parse () Step 4: Return the Configuration object. Configuration =parse(); // Create SqlSessionFactory with Configuration object. SqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);

In the figure above, 4.1 and 4.2 only return an empty Configuration object, while 5-11 only return a constructed Configuration object, which is different.

3.5 Summary: Manually load the XML Configuration file. Create a Configuration object. After initialization, create and use the SqlSessionFactory object

We can use XMLConfigBuilder to manually parse the XML Configuration file to create a Configuration object as follows:

String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, null,null); Configuration configuration=parse(); SqlSessionFactory SqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration); / / use MyBatis SqlSession SqlSession = sqlSessionFactory. OpenSession (); List list = sqlSession.selectList("com.foo.bean.BlogMapper.queryAllBlogInfo");
Copy the code

Summary: Design patterns involved in Mybatis initialization

The initialization process involves creating various objects, so some creative design patterns are used. In the process of initialization, Builder mode is used more.

4.1 Application of Builder Mode 1: creation of SqlSessionFactory

When creating a SqlSessionFactory, different parameters are provided depending on the situation. The parameter combinations can be as follows:

Since the construction parameters are variable, we can create a constructor for it to separate the construction process from the representation of SqlSessionFactory:

MyBatis separates SqlSessionFactoryBuilder and SqlSessionFactory from each other.

4.2 Application in Builder Mode 2: Creating the Environment object for database connection

When XMLConfigParser parses the Mybatis XML Configuration file node node during the construction of the Configuration object, there is the following code:

  private void environmentsElement(XNode context) throws Exception {
    if(context ! = null) {if (environment == null) {
        environment = context.getStringAttribute("default");
      }
      for (XNode child : context.getChildren()) {
        String id = child.getStringAttribute("id"); // It is the same as the default environmentif (isSpecifiedEnvironment(id)) {
          TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource")); DataSource dataSource = dsFactory.getDataSource(); // Use the built-in Environment Builder, Environment.builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory) .dataSource(dataSource); configuration.setEnvironment(environmentBuilder.build()); }}}}Copy the code

Inside the Environment, the static inner Builder class is defined:

public final class Environment {
  private final String id;
  private final TransactionFactory transactionFactory;
  private final DataSource dataSource;
 
  public Environment(String id, TransactionFactory transactionFactory, DataSource dataSource) {
    if (id == null) {
      throw new IllegalArgumentException("Parameter 'id' must not be null");
    }
    if (transactionFactory == null) {
        throw new IllegalArgumentException("Parameter 'transactionFactory' must not be null");
    }
    this.id = id;
    if (dataSource == null) {
      throw new IllegalArgumentException("Parameter 'dataSource' must not be null");
    }
    this.transactionFactory = transactionFactory;
    this.dataSource = dataSource;
  }
 
  public static class Builder {
      private String id;
      private TransactionFactory transactionFactory;
      private DataSource dataSource;
 
    public Builder(String id) {
      this.id = id;
    }
 
    public Builder transactionFactory(TransactionFactory transactionFactory) {
      this.transactionFactory = transactionFactory;
      return this;
    }
 
    public Builder dataSource(DataSource dataSource) {
      this.dataSource = dataSource;
      return this;
    }
 
    public String id() {
      return this.id;
    }
 
    public Environment build() {
      return new Environment(this.id, this.transactionFactory, this.dataSource);
    }
 
  }
 
  public String getId() {
    return this.id;
  }
 
  public TransactionFactory getTransactionFactory() {
    return this.transactionFactory;
  }
 
  public DataSource getDataSource() {
    returnthis.dataSource; }}Copy the code

Five, the summary

Initialization of Mybatis, complete.

Play code every day, progress every day!!