千里皓月

V1

2022/08/20阅读:8主题:凝夜紫

连小公司都开始问MyBatis底层源码了?如何简练回答面试官MyBatis底层原理?

两天前,舍友大方去面试了一家小公司

面试官:看你的简历上写着 ”熟练使用MyBatis“,你对 MyBatis 很了解咯

大方:是的,我能熟练使用 MyBatis 的增删查改,以及动态查询

面试官:那你看过 MyBatis 的底层源码吗?

大方:啊,这个我没有看过诶…

面试官:没事,你回去等通知吧

那如何简洁地回答 MyBatis 的源码呢?

相信大家对 MyBatis 的构建流程已经很熟悉了吧!

public static void init() throws IOException {
    // 加载MyBatis.xml文件
    in = Resources.getResourceAsStream("classpath:MyBatis-Config.xml");
    // 通过SqlSessionFactoryBuilder的build方法加载输入流,构建SqlSessionFactory
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(in);
    // 执行OpenSession方法
    session = factory.openSession();
    // 调用getMapper获取mapper接口类
    videoMapper = session.getMapper(VideoMapper.class);
}

顺着这个流程,我们简单讲一下底层原理

getResourceAsStream() 是一个加载文件并转化为输入流的方法,这个就不需要多说了。

重点放在这个build方法,我们看看build方法中写了什么

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
  try {
    XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
      // 通过 Xml解析器解析mybatis.xml文件,并调用parse方法
    return build(parser.parse());
  } catch (Exception e) {
  } finally {
    try {
      inputStream.close();
    } catch (IOException e) {
    }
  }
}

这个parse就是核心解析方法了,他xml文件中每个节点进行解析,解析并将数据加载到框架中

看他加载了这么多节点,一开始他解析最大的父节点《configuration》,解析出多种子节点并对子节点接着解析。

我们重点看这两个节点的解析,一个是environment节点的解析,解析完成后加载mybatis环境

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");
      if (isSpecifiedEnvironment(id)) {
        TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
          // 获取数据源,我们已经编写好的url、driver、username、password
        DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
        DataSource dataSource = dsFactory.getDataSource();
          // 通过构建器模式构建出环境,并设置到configuration中
        Environment.Builder environmentBuilder = new Environment.Builder(id)
            .transactionFactory(txFactory)
            .dataSource(dataSource);
        configuration.setEnvironment(environmentBuilder.build());
      }
    }
  }
}

上面这一步设置环境是重点中的重点,有了上面这一步,mybatis才能正常启动起来

另外一个节点就是mapper节点,官网上写着mapper的几种实现方式:package、resource、url、class,这里就不详细介绍,这里是通过节点属性解析之后,获取mapper.xml的加载方式,最终解析并

最终,我们会进入这个方法

这个方法就是加载mapper.xml文件中sql语句的方法,加载完sql语句后,存放在mappedStatement中

至此,build构建方法加载完毕,接下来就是OpenSession方法

其实这个方法也很简单,重点就是这个 newTransaction 方法,他封装了 JDBC 底层的代码

诺!这些方法是不是很熟悉

有了 jdbc 的方法后,接下来就是 sql 语句的执行了

继续点击底层查看代码,在点击 MapperProxyFactory 这个类的时候,我们发现,mybatis 通过代理模式,动态地创建mapper

我们点击 MapperProxy 进入查看

在这个方法中,我们突然发现 MapperMethod 最后调用了 execute 解析方法!我们点进去查看一下这个解析方法实现了什么

哇哦!增删查改都写在这里了,四种类型的数据库操作方法,也同时对应封装好了返回结果

mybatis 的原理流程大概就是这样子过了一遍,当然,这不是全部,有很多我们没有深入的地方如XNode节点、缓存等等,有兴趣可以一起讨论。

哎呀!好像讲到这里有点乱,我来总结一下整个流程吧!

一开始,我们需要跟面试官说明一下,什么是 ORM 框架,实际上很多同学知道 ORM 框架有 MyBatis、Hibernate、Jpa等,但是并不能说明白 ORM 框架是什么?

ORM 框架就是将 Java 中的对象实体,与数据库表关联起来并一一对应的框架。比如,将 user 表和 User pojo 绑定在一起,将数据库中的 varchar 与 Java 中的 String 对应起来,

  • 首先,调用 Resources.getResourceAsStream() 方法加载 MyBatis-Config.xml 文件
  • 接着,通过 build() 方法加载输入流
  • 通过 XmlConfigBuilder 执行 parse() 对xml 文件中的节点进行解析
  • 在 parse 解析中,最重要解析的两个节点,分别是 environments 和 mappers
  • 解析 environments ,并将其放到 configuration 中
  • 解析 mappers,并将它们放到 kownmapper 中
  • 接着执行 OpenSession 方法,这个方法封装了 jdbc 底层的数据库操作方法
  • 通过 getMapper 方法,调用我们需要的 mapper 接口
  • 并通过 jdk 的动态代理,为我们代理了 MapperMethod 类
  • 调用 excute() 方法,我们发现这里已经写好了增删查改的方法,最终返回mybatis为我们封装好的result结果集

分类:

后端

标签:

后端

作者介绍

千里皓月
V1