自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Mybatis是如何解析配置文件的?看完終于明白了

開發(fā) 前端
在以前文章中,我們把Mybatis源碼閱讀的整個(gè)流程梳理了一遍。今天,我們來詳細(xì)聊聊,Mybatis是如何解析配置文件的。

[[357645]]

在以前文章中,我們把Mybatis源碼閱讀的整個(gè)流程梳理了一遍。今天,我們來詳細(xì)聊聊,Mybatis是如何解析配置文件的。

這是今天分析的流程圖:

 

還是從案例開始。

demo案例

  1. public static void main(String[] args) { 
  2.         String resource = "mybatis-config.xml"
  3.         InputStream inputStream = null
  4.         SqlSession sqlSession = null
  5.         try { 
  6.             inputStream = Resources.getResourceAsStream(resource); 
  7.             SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 
  8.             sqlSession = sqlSessionFactory.openSession(); 
  9.  
  10.             UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 
  11.             System.out.println(userMapper.selectById(1)); 
  12.  
  13.         } catch (Exception e) { 
  14.             e.printStackTrace(); 
  15.         } finally { 
  16.             try { 
  17.                 inputStream.close(); 
  18.             } catch (IOException e) { 
  19.                 e.printStackTrace(); 
  20.             } 
  21.             sqlSession.close(); 
  22.         } 
  23.     } 

見證奇跡

從SqlSessionFactoryBuilder開始。

SqlSessionFactoryBuilder類

  1. org.apache.ibatis.session.SqlSessionFactoryBuilder 

該類里全是build方法各種重載。

  1. //這個(gè)方法啥也沒干   
  2. public SqlSessionFactory build(InputStream inputStream) { 
  3.     return build(inputStream, nullnull); 
  4.  } 

最終來到另外一個(gè)build方法里:

  1. public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) { 
  2.    try { 
  3.      //創(chuàng)建一個(gè)XMLConfigBuilder對象   
  4.      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties); 
  5.      return build(parser.parse()); 
  6.    } catch (Exception e) { 
  7.      throw ExceptionFactory.wrapException("Error building SqlSession.", e); 
  8.    } finally { 
  9.      ErrorContext.instance().reset(); 
  10.      try { 
  11.        inputStream.close(); 
  12.      } catch (IOException e) { 
  13.        // Intentionally ignore. Prefer previous error. 
  14.      } 
  15.    } 
  16.  } 

XMLConfigBuilder類

該類的構(gòu)造方法重載:

 

首先進(jìn)入:

  1. public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) { 
  2.     this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment,      
  3.          props); 
  4. private XMLConfigBuilder(XPathParser parser, String environment, Properties props) { 
  5.     super(new Configuration()); 
  6.     ErrorContext.instance().resource("SQL Mapper Configuration"); 
  7.     this.configuration.setVariables(props); 
  8.     this.parsed = false
  9.     this.environment = environment; 
  10.     this.parser = parser; 

build(parser.parse());中的parser.parse();

mybatis-config.xml在哪里解析的呢?

請看下面這個(gè)方法:

  1. //該方法返回一個(gè)Configuration對象 
  2. public Configuration parse() { 
  3.   if (parsed) { 
  4.     throw new BuilderException("Each XMLConfigBuilder can only be used once."); 
  5.   } 
  6.   parsed = true
  7.   //關(guān)鍵點(diǎn) 
  8.   parseConfiguration(parser.evalNode("/configuration")); 
  9.   return configuration; 

parseConfiguration(parser.evalNode("/configuration"));

終于看到開始解析配置文件了:

 

進(jìn)入方法parseConfiguration。

  1. private void parseConfiguration(XNode root) { 
  2.   try { 
  3.     //issue #117 read properties first 
  4.     propertiesElement(root.evalNode("properties")); 
  5.     Properties settings = settingsAsProperties(root.evalNode("settings")); 
  6.     loadCustomVfs(settings); 
  7.     loadCustomLogImpl(settings); 
  8.     typeAliasesElement(root.evalNode("typeAliases")); 
  9.     pluginElement(root.evalNode("plugins")); 
  10.     objectFactoryElement(root.evalNode("objectFactory")); 
  11.     objectWrapperFactoryElement(root.evalNode("objectWrapperFactory")); 
  12.     reflectorFactoryElement(root.evalNode("reflectorFactory")); 
  13.     settingsElement(settings); 
  14.     // read it after objectFactory and objectWrapperFactory issue #631 
  15.     environmentsElement(root.evalNode("environments")); 
  16.     databaseIdProviderElement(root.evalNode("databaseIdProvider")); 
  17.     typeHandlerElement(root.evalNode("typeHandlers")); 
  18.     mapperElement(root.evalNode("mappers")); 
  19.   } catch (Exception e) { 
  20.     throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e); 
  21.   } 

這里就是把mybatis-config.xml內(nèi)容解析,然后設(shè)置到Configuration對象中。

那么我們定義的Mapper.xml是在哪里解析的呢?

我們的Mapper.xml在mybatis-config.xml中的配置是這樣的:

 

使用方式有以下四種:

  1. //1使用類路徑 
  2. <mappers> 
  3.     <mapper resource="org/mybatis/builder/AuthorMapper.xml"/> 
  4.       <mapper resource="org/mybatis/builder/BlogMapper.xml"/> 
  5.    <mapper resource="org/mybatis/builder/PostMapper.xml"/> 
  6. </mappers> 
  7. //2使用絕對url路徑 
  8. <mappers> 
  9.    <mapper url="file:///var/mappers/AuthorMapper.xml"/> 
  10.    <mapper url="file:///var/mappers/BlogMapper.xml"/> 
  11.    <mapper url="file:///var/mappers/PostMapper.xml"/> 
  12. </mappers> 
  13. //3使用java類名 
  14. <mappers> 
  15.    <mapper class="org.mybatis.builder.AuthorMapper"/> 
  16.    <mapper class="org.mybatis.builder.BlogMapper"/> 
  17.    <mapper class="org.mybatis.builder.PostMapper"/> 
  18. </mappers> 
  19.  
  20. //4自動掃描包下所有映射器 
  21. <mappers> 
  22.    <package name="org.mybatis.builder"/> 
  23. </mappers> 

繼續(xù)源碼分析,我們在上面mybatis-config.xml解析中可以看到:

 

我們不妨進(jìn)入這個(gè)方法看看:

  1. private void mapperElement(XNode parent) throws Exception { 
  2.    if (parent != null) { 
  3.      for (XNode child : parent.getChildren()) { 
  4.        //自動掃描包下所有映射器 
  5.        if ("package".equals(child.getName())) { 
  6.          String mapperPackage = child.getStringAttribute("name"); 
  7.          //放   
  8.          configuration.addMappers(mapperPackage); 
  9.        } else { 
  10.          String resource = child.getStringAttribute("resource"); 
  11.          String url = child.getStringAttribute("url"); 
  12.          String mapperClass = child.getStringAttribute("class"); 
  13.          //使用java類名 
  14.          if (resource != null && url == null && mapperClass == null) { 
  15.            ErrorContext.instance().resource(resource); 
  16.             //根據(jù)文件存放目錄,讀取XxxMapper.xml 
  17.            InputStream inputStream = Resources.getResourceAsStream(resource); 
  18.             //映射器比較復(fù)雜,調(diào)用XMLMapperBuilder 
  19.            //注意在for循環(huán)里每個(gè)mapper都重新new一個(gè)XMLMapperBuilder,來解析 
  20.            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); 
  21.            mapperParser.parse(); 
  22.          //使用絕對url路徑 
  23.          } else if (resource == null && url != null && mapperClass == null) { 
  24.            ErrorContext.instance().resource(url); 
  25.            InputStream inputStream = Resources.getUrlAsStream(url); 
  26.            //映射器比較復(fù)雜,調(diào)用XMLMapperBuilder 
  27.            XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); 
  28.            mapperParser.parse(); 
  29.          //使用類路徑     
  30.          } else if (resource == null && url == null && mapperClass != null) { 
  31.            Class<?> mapperInterface = Resources.classForName(mapperClass); 
  32.            //直接把這個(gè)映射加入配置 
  33.            configuration.addMapper(mapperInterface); 
  34.          } else { 
  35.            throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); 
  36.          } 
  37.        } 
  38.      } 
  39.    } 
  40.  } 

這里剛剛和我們的上面說的使用的方式完全是一模一樣的。

到這里,配置文件mybatis-config.xml和我們定義映射文件XxxMapper.xml就全部解析完成。

回到SqlSessionFactoryBuilder類

前面講到了XMLConfigBuilder中的parse方法,并返回了一個(gè)Configuration對象。

build(parser.parse());

這個(gè)build方法就是傳入一個(gè)Configuration對象,然后構(gòu)建一個(gè)DefaultSqlSession對象。

  1. public SqlSessionFactory build(Configuration config) { 
  2.   return new DefaultSqlSessionFactory(config); 

繼續(xù)回到我們的demo代碼中這一行代碼里:

  1. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); 

這一行代碼就相當(dāng)于:

  1. SqlSessionFactory sqlSessionFactory = new new DefaultSqlSessionFactory(); 

 

到這里,我們的整個(gè)流程就搞定了。

本文轉(zhuǎn)載自微信公眾號「 Java后端技術(shù)全棧  」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 Java后端技術(shù)全棧  公眾號。

 

責(zé)任編輯:武曉燕 來源: Java后端技術(shù)全棧
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號