前言

GitHub Fork一份MyBatis源码后,我们在IDE中打开,运行测试用例AutoConstructorTest类中的fullyPopulatedSubject()方法,为了找到熟悉的感觉,我在同级目录的AutoConstructorMapper类和AutoConstructorMapper.xml文件对应添加了一个findById的查询。

加载全局配置文件流程

Tips:可以用Debug的模式来运行来打断点,看看Configuration中的值

1.加载全局配置文件mybatis-config.xml

  1. try (Reader reader = Resources.getResourceAsReader("org/apache/ibatis/autoconstructor/mybatis-config.xml")) {
  2. // 调用 #1
  3. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
  4. }

2.SqlSessionFactoryBuilder类中生成SqlSessionFactory

  1. // #1
  2. public SqlSessionFactory build(Reader reader) {
  3. // 调用#2
  4. return build(reader, null, null);
  5. }
  6. // #2
  7. public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
  8. try {
  9. XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
  10. // 调用#3 parser.parse()
  11. // 调用#4
  12. return build(parser.parse());
  13. } catch (Exception e) {
  14. throw ExceptionFactory.wrapException("Error building SqlSession.", e);
  15. } finally {
  16. ErrorContext.instance().reset();
  17. try {
  18. reader.close();
  19. } catch (IOException e) {
  20. // Intentionally ignore. Prefer previous error.
  21. }
  22. }
  23. }

3.XMLConfigBuilder类中解析Configuration

  1. // #3
  2. public Configuration parse() {
  3. if (parsed) {
  4. throw new BuilderException("Each MyXMLConfigBuilder can only be used once.");
  5. }
  6. parsed = true;
  7. // 调用#5
  8. parseConfiguration(parser.evalNode("/configuration"));
  9. return configuration;
  10. }
  11. // #5 XPathParser解析器会解析各种标签
  12. private void parseConfiguration(XNode root) {
  13. try {
  14. //issue #117 read properties first
  15. propertiesElement(root.evalNode("properties"));
  16. Properties settings = settingsAsProperties(root.evalNode("settings"));
  17. loadCustomVfs(settings);
  18. loadCustomLogImpl(settings);
  19. typeAliasesElement(root.evalNode("typeAliases"));
  20. pluginElement(root.evalNode("plugins"));
  21. objectFactoryElement(root.evalNode("objectFactory"));
  22. objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
  23. reflectorFactoryElement(root.evalNode("reflectorFactory"));
  24. settingsElement(settings);
  25. // read it after objectFactory and objectWrapperFactory issue #631
  26. environmentsElement(root.evalNode("environments"));
  27. databaseIdProviderElement(root.evalNode("databaseIdProvider"));
  28. typeHandlerElement(root.evalNode("typeHandlers"));
  29. mapperElement(root.evalNode("mappers"));
  30. } catch (Exception e) {
  31. throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
  32. }
  33. }

4.获取Configuration对象

image.png

image.png

经过以上几个步骤就会得到Configuration这个超级复杂的核心对象。

如图所示,拿其中mappedStatements来说,是个Map结构,它里面的key存储的就是*Mapper.xml中select/insert/update/delete标签中的id值,这里我们看findById,里面的mappedStatement存储这个关于这个statement的各种信息,statement的id由namespace+标签中的id来保证唯一性,具体细节可以打个断点查看下。

dataSource也正是我们从mybatis-config.xml文件中加载到的数据源配置项。

5.通过Configuration获取到SqlSessionFactory

  1. // #4
  2. public SqlSessionFactory build(Configuration config) {
  3. // 使用DefaultSqlSessionFactory创建
  4. return new DefaultSqlSessionFactory(config);
  5. }

小结

本篇通过MyBatis提供的AutoConstructorTest测试类,我们跟踪了下全局配置文件的加载流程,xml中配置的一个标签最终都会对应着一个Configuration类,最后生成SqlSessionFactory。

本篇只是粗略的探讨了几个主要的类:

  • SqlSessionFactoryBuilder
  • XMLConfigBuilder
  • Configuration
  • XPathParser
  • SqlSessionFactory

但其实在XMLConfigBuilder中解析各个标签用到的XNode和其他一些类就没有去关心了或者说不是本篇的重点,正如第一篇讲到,把控好主线才不容易走丢。

请你相信我所说的都是错的