Whether using XML configuration, annotation configuration, or Boot mode, we only need to specify the path of mybatis-config configuration and Mapper XML file during configuration, and then the interface uses Mapper interface to operate on the database just like any other bean in Spring. The reason, of course, is that when the container is initialized, the configuration of the Mapper XML file is parsed and injected into the Spring container for use when we need it, which is dissected below to see how Spring and Mybtais help us.

Mybatis with Spring is the most common usage pattern, we just need to introduce Mybatis – Spring dependency.

Mybatis native initialization

First, let’s see how Mybatis can be used without Spring dependency. See Mybait’s official documentation for an example:

// Build SqlsessionFactory without XML
DataSource dataSource = BlogDataSourceFactory.getBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment("development", transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.addMapper(BlogMapper.class);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
 
/ / get the SqlSession
try (SqlSession session = sqlSessionFactory.openSession()) {
  BlogMapper mapper = session.getMapper(BlogMapper.class);
  Blog blog = mapper.selectBlog(101);
}
Copy the code

The first step is to build the SqlSessionFactory, which can be built in XML, giving you more steps to parse XML files than you would without XML. (See mybatis.org/mybatis-3/z…)

The key process can be seen in the above demo. The final purpose of initialization is to form an instance of SqlSessionFactory. The instance contains a Configuration object.

The initialization is done in the SqlSessionFactoryBuilder as follows:

public class SqlSessionFactoryBuilder {
 
    public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            return build(parser.parse());
        } 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.}}}public SqlSessionFactory build(Configuration config) {
    return newDefaultSqlSessionFactory(config); }}public class XMLConfigBuilder extends BaseBuilder {
    public Configuration parse(a) {
    if (parsed) {
      throw new BuilderException("Each XMLConfigBuilder can only be used once.");
    }
    parsed = true;
    // Parse the Configuration file mybatis-config. XML and save the contents of the XML Configuration in the Configuration object
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
 
private void parseConfiguration(XNode root) {
    try {
      / /... Parse each category in the configuration file in turn
       
      // Parse Mapper XML configuration
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: "+ e, e); }}private void mapperElement(XNode parent) throws Exception {
    if(parent ! =null) {
      for (XNode child : parent.getChildren()) {
        / / scan packages
        if ("package".equals(child.getName())) {
          String mapperPackage = child.getStringAttribute("name");
            // Add a Mapper interface to the configuration
            configuration.addMappers(mapperPackage);
        } else {
          String resource = child.getStringAttribute("resource");
          String url = child.getStringAttribute("url");
          String mapperClass = child.getStringAttribute("class");
          if(resource ! =null && url == null && mapperClass == null) {
            ErrorContext.instance().resource(resource);
            InputStream inputStream = Resources.getResourceAsStream(resource);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null&& url ! =null && mapperClass == null) {
            ErrorContext.instance().resource(url);
            InputStream inputStream = Resources.getUrlAsStream(url);
            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());
            mapperParser.parse();
          } else if (resource == null && url == null&& mapperClass ! =null) { Class<? > mapperInterface = Resources.classForName(mapperClass); configuration.addMapper(mapperInterface); }else {
            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");
          }
        }
      }
    }
  }
}
Copy the code

Can see in the end is through Configutration. AddMappers to add Mapper interfaces to complete Mapper the initialization of the interface.

Mybatis – Spring initialization

In SqlSesssionFactoryBean, here is an example of creating the SqlSessionFactory code (or via XML configuration loading) :

@Configuration
public class MyBatisConfig {
  @Bean
  public SqlSessionFactory sqlSessionFactory(a) throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    // Set DataSource
    factoryBean.setDataSource(dataSource());
 
    PathMatchingResourcePatternResolver pmrpr = new PathMatchingResourcePatternResolver();
     
 
    Resource configLocation = pmrpr.getResource("classpath:META-INF/mybatis/mybatis-config.xml");
    factoryBean.setConfigLocation(configLocation); 
 
    Resource[] configResource = pmrpr.getResources("classpath*:META-INF/mybatis/mapper/*.xml");
    factoryBean.setMapperLocations(configResource);
 
    returnfactoryBean.getObject(); }}Copy the code

When creating the SqlSessionFactory, the most important thing is to set up a DataSource. Also set the myBait configuration file mybatis-config. XML and the Mapper XML file path.

The specific initialization process is as follows:

protected SqlSessionFactory buildSqlSessionFactory(a) throws IOException {
 
    Configuration configuration;
 
    XMLConfigBuilder xmlConfigBuilder = null;
    if (this.configuration ! =null) {
      configuration = this.configuration;
      if (configuration.getVariables() == null) {
        configuration.setVariables(this.configurationProperties);
      } else if (this.configurationProperties ! =null) {
        configuration.getVariables().putAll(this.configurationProperties); }}else if (this.configLocation ! =null) {
      // Initialize XMLConfigBuilder for mybatis configuration file
      xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null.this.configurationProperties);
      configuration = xmlConfigBuilder.getConfiguration();
    } else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatis Configuration");
      }
      configuration = new Configuration();
      if (this.configurationProperties ! =null) {
        configuration.setVariables(this.configurationProperties); }}// Omit the loading of other configurations
 
    if(xmlConfigBuilder ! =null) {
      try {
        xmlConfigBuilder.parse();
 
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed configuration file: '" + this.configLocation + "'"); }}catch (Exception ex) {
        throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
      } finally{ ErrorContext.instance().reset(); }}// Transaction management Factory
    if (this.transactionFactory == null) {
      this.transactionFactory = new SpringManagedTransactionFactory();
    }
 
    configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
 
    // mapper XML is not empty
    if(! isEmpty(this.mapperLocations)) {
      for (Resource mapperLocation : this.mapperLocations) {
        if (mapperLocation == null) {
          continue;
        }
 
        try {
        // Load the parse Mapper XML file
          XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
              configuration, mapperLocation.toString(), configuration.getSqlFragments());
          xmlMapperBuilder.parse();
        } catch (Exception e) {
          throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
        } finally {
          ErrorContext.instance().reset();
        }
 
        if (LOGGER.isDebugEnabled()) {
          LOGGER.debug("Parsed mapper file: '" + mapperLocation + "'"); }}}else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found"); }}return this.sqlSessionFactoryBuilder.build(configuration);
  }
Copy the code

The entire process of loading the configuration is basically the same as the native process, with SqlSesssionFactoryBean as the entry point for adaptation.

Third, summary

The initialization process is to construct a SqlSessionFactory for subsequent SqlSession creation, and the most important object SqlSessionFactory contains is Configuration, The Configuration object will load all the Configuration information of Mybatis.

Using our most commonly used configuration files XML and Mapper XML files to illustrate the core steps of initialization:

1, according to the configuration of mybatis-config. XML path and Mapper XML package path, load into Resource;

2. Use XMLConfigBuiler to parse the Configuration of mybatis-config. XML and set it into the Configuration object.

3. Use XMLMapperBuilder to parse Mapper XML resources, and use addMapper or addMappers on Configuration to initialize the Mapper interface into the container;

For details of specific configurations, such as plug-in configuration, look at the parse process for XMLConfigBuiler, and XMLMapperBuilder for parsing and loading the Mapper XML file.