干翻Mybatis源码系列之第五篇:Mybatis中核心运行机制超级详细版

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 干翻Mybatis源码系列之第五篇:Mybatis中核心运行机制超级详细版

一:引言

1:本文目的

熟悉花哥的都知道,花哥是该粗的地方粗该细的地方细,写文章的话咱追求的还是细致和全面,所以本文意在将Mybatis从SqlSessionFactory被创建出来到Dao被执行成功,我们会将绝大部分的细节写的到位,这是我们本专栏也是本篇文章的目的。

2:首要知识回顾

1:在我们使用原生Mybatis的时候,我们获取UserDao的实现类对象,还得向下面这么写。基于Spring整合Mybatis之后,我们也就只会拿着userDao.xxx()这样进行操作了。然而,我们要知道下文中几行代码,才能体现Mybatis真正的运行过程。

//通过这一步将Mybatis配置文件读取到我们的JVM中。
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
//接下来就该创建SqlSessionFactory和SqlSession对象了。
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStram);
SqlSession sql = sqlSessionFactory.openSession);
//获取到具体的UserDao接口的代理对象
UserDao userDao = sqlSession.getMapper(UserDao.class);
//基于实际的JDBC的
int result = userDao.save();
List<User> users= userDao.query();

3:知识补充

1):Mybatis如何处理XML文件

1:任何配置读取到JVM当中一定是以对象的形式体现的,封装成一个一个存储类型的对象,存储在JVM的用户内存中。

2:Mybatis的核心配置文件Mybatis-config.xml会被封装成Configuration对象,读取XML相关内容。

3:Mybatis中的Mapper.xml文件则是被打散了,这种标签则是被封装到MappedStatement对象中,剩余的标签则是被封装到

各种类型的对象基于放到Map当中,key是nameSpace.id的形式,并且浙西对象都保存到了Configuration当中,Configuration和MappedStatement是双向引用。

4:Java当中XML解析的方式有三种:DOM SAX XPath,Mybatis在处理XML的过程当中使用的是Xpath

5:XPathParser解析了Xml之后初步解析成为一个XNode对象。

6:Configuration和MappedStatement是Mybatis当中的最核心的两个存储类对象。

2):测试使用Mybatis中API解析XML

XPathParser xpathPaser = new XPathParser(InputStream)

通过标签Node的方式就可以获取到一个一个标签的具体的内容。

@Test
    public void testXml() throws IOException {
        //InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        //Reader reader = Resources.getResourceAsReader("users.xml");
        InputStream inputStream = Resources.getResourceAsStream("users.xml");
        XPathParser xPathParser = new XPathParser(inputStream);
        //xNodes 里面的xNode 对应 <user>
        //  /configuration/*,要读取这个根标签下的所有的内容
        List<XNode> xNodes = xPathParser.evalNodes("/users/*");
        //要读取这个/users标签中下的所有的标签。
        List<com.baizhiedu.xml.User> users = new ArrayList<>();
        //这里面每一个xNode对应就是一个<user>
        for (XNode xNode : xNodes) {
            com.baizhiedu.xml.User user = new com.baizhiedu.xml.User();
            List<XNode> children = xNode.getChildren();
            user.setName(children.get(0).getStringBody());
            user.setPassword(children.get(1).getStringBody());
            users.add(user);
        }
        for (com.baizhiedu.xml.User user : users) {
            System.out.println("user = " + user);
        }
    }
<users>
    <user>
        <name>sunshuai</name>
        <password>2222</password>
    </user>
    <user>
        <name>xiaohei</name>
        <password>2222</password>
    </user>
</users>

以上这个内容是在对应到Mybatis框架当中是在:build方法当中完成的InputStream – XNode – Configuration的解析。

//----------------------------删除------------------------------------//

整个Mybatis的操作就是两大块,一个是获取Dao之后的操作,另外一个就是获取SqlSession的操作,把这几大块内容搞清楚了,我们大致的东西就搞明白了。

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");

这块是最没有歧义的,这块就是通过IO的方式通过获取Mybatis-config.xml和xxxMapper.xml的中的配置内容。

我们上边虽然只读取了Mybatis.xml配置文件当中的内容,但是顺便也会把Mapper.xml当中的脚本,这是基于Mybatis-config.xml当中的Mapper标签,将所有的Mapper.xml找到,读取到JVM内存中,封装到对应的对象当中。

//----------------------------删除------------------------------------//

三:Mybatis核心运行过程

1:new SqlSessionFactoryBuilder().build(inputStram)详解

InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStram);

build方法是来自于SqlSessionFactoryBuilder,SqlSessionFactory 也是需要SqlSessionFactoryBuilder来进行创建的。

点击去build方法之后我们可以看到:

public SqlSessionFactory build(InputStream inputStream) {
        return this.build((InputStream)inputStream, (String)null, (Properties)null);
    }

这个方法调用的是下面这个重载的方法:

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
        SqlSessionFactory var5;
        try {
            XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
            //parser.parse()的返回值:Configuration 
            //var5 是SqlSessionFactory 
            var5 = this.build(parser.parse());
        } catch (Exception var14) {
            throw ExceptionFactory.wrapException("Error building SqlSession.", var14);
        } finally {
            ErrorContext.instance().reset();
            try {
                inputStream.close();
            } catch (IOException var13) {
            }
        }
        return var5;
    }

到这里我们可以清楚的看到,parser.parse()方法已经将核心存储类Configuration创建出来了,build(Configuration) 将SqlSessionFactory对象创建出来了。

1):new XMLConfigBuilder()

对于处理XML文件Mybatis当中有两个核心的类:XPathParser和XMLConfigBuilder,经过一系列的读取之后,将Mybatis核心配置文件的内容暂时放置到了XMLConfigBuilder.XPathParser.Document当中:

XMLConfigBuilder:

public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
    }

XPathParser:

private final Document document;
    public XPathParser(InputStream inputStream, boolean validation, Properties variables, EntityResolver entityResolver) {
        this.commonConstructor(validation, variables, entityResolver);
        this.document = this.createDocument(new InputSource(inputStream));
    }

2):XMLConfigBuilder.parse()

public Configuration parse() {
        if (this.parsed) {
            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
        } else {
            this.parsed = true;
            //parser.evalNode("/configuration")这个是将Mybatis-config.xml中的configuration标签整个拿了出来。
            this.parseConfiguration(this.parser.evalNode("/configuration"));
            return this.configuration;
        }
    }

parser.evalNode(“/configuration”)这个是将Mybatis-config.xml中的configuration标签整个拿了出来,返回值是一个XNode对象。parseConfiguration(XNode)的返回值是核心的Configuration对象,并且在此处也将关键的 MappedStatement也创建了出来,并在

Configuration对象当中以:

protected final Map<String, MappedStatement> mappedStatements;

存在,至此Mybatis存存储类对象Configuration+MappedStatement都已经创建完毕!

补充说明:此处对于Configuration+MappedStatement的说明不够详细,我们后续会将详解版专门写一篇文章,链接至于此处。

2):this.build(parser.parse());

public SqlSessionFactory build(Configuration config) {
        return new DefaultSqlSessionFactory(config);
    }

在这里SqlSessionFactory也基于重载build(Configuration config)方法被创建出来。

2:sqlSessionFactory.openSession详解

待补充!

3:sqlSession.getMapper(UserDao.class)详解

我们基于sqlSessionFactory.openSession()创建的SqlSession的类型是:DefaultSqlSession,基于上述代码路径一路走到了MapperProxyFactory的类中,这是Mybatis当中创建UserDao代理对象的核心对象之一,另外一个是MapperProxy,基于二者Mybatis创建出来了UserDao的代理对象,最终代码如下:

protected T newInstance(MapperProxy<T> mapperProxy) {
        return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
    }

MapperProxy是InvocationHandler的代理类

public class MapperProxy<T> implements InvocationHandler, Serializable {
  ...
}

Mybatis再次创建接口的代理对象正是基于JDK提供的Proxy.newInstance()的方式:

Proxy.newProxyInstance(ClassLoader classLoader, Class[] clazzs, InvocationHandler invocationHandler);

我们知道JDK创建代理对象的方式是将额外功能书写到了InvocationHandler.invoke()方法中。

@Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      } else if (isDefaultMethod(method)) {
        return invokeDefaultMethod(proxy, method, args);
      }
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
    final MapperMethod mapperMethod = cachedMapperMethod(method);
    return mapperMethod.execute(sqlSession, args);
  }

这里值得注意的是

4:userDao.query()详解

UserDao userDao = sqlSession.getMapper(UserDao.class);以下部分是我们的关注点,我们通过动态代理构建了Dao的实现类,并创建了他的对象。

Mybatis在这里是通过两种关键类型做的

1:MapperProxyFactory(JDK创建的代理 )
2:MapperProxy代理的就是MapperProxy的代理。
      3:SqlCommand
              |-- type [insert update select delete]
              |-- name  namespace.id
      4:MethodSingnatrue
                      |-- 方法的返回值
              |-- 方法的参数
  | -- sqlSession.update();
              |-- Excutor (SimpleExcutor,ReuseExcutor....)
                  |-- StatementHandler
                      |-- ParameterHandler  ResultSetHandler
                            TypeHandler

备注:此文章未完待续…

相关文章
|
2月前
|
缓存 Java 数据库连接
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
文章介绍了MyBatis的缓存机制,包括一级缓存和二级缓存的配置和使用,以及如何整合第三方缓存EHCache。详细解释了一级缓存的生命周期、二级缓存的开启条件和配置属性,以及如何通过ehcache.xml配置文件和logback.xml日志配置文件来实现EHCache的整合。
mybatis复习05,mybatis的缓存机制(一级缓存和二级缓存及第三方缓存)
|
2月前
|
SQL XML Java
mybatis-源码深入分析(一)
mybatis-源码深入分析(一)
|
11天前
|
SQL Java 数据库连接
Mybatis架构原理和机制,图文详解版,超详细!
MyBatis 是 Java 生态中非常著名的一款 ORM 框架,在一线互联网大厂中应用广泛,Mybatis已经成为了一个必会框架。本文详细解析了MyBatis的架构原理与机制,帮助读者全面提升对MyBatis的理解和应用能力。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Mybatis架构原理和机制,图文详解版,超详细!
|
1月前
|
前端开发 Java 数据库连接
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
本文是一份全面的表白墙/留言墙项目教程,使用SpringBoot + MyBatis技术栈和MySQL数据库开发,涵盖了项目前后端开发、数据库配置、代码实现和运行的详细步骤。
51 0
表白墙/留言墙 —— 中级SpringBoot项目,MyBatis技术栈MySQL数据库开发,练手项目前后端开发(带完整源码) 全方位全步骤手把手教学
|
1月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
136 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
3月前
|
XML Java 数据库连接
mybatis源码研究、搭建mybatis源码运行的环境
这篇文章详细介绍了如何搭建MyBatis源码运行的环境,包括创建Maven项目、导入源码、添加代码、Debug运行研究源码,并提供了解决常见问题的方法和链接到搭建好的环境。
mybatis源码研究、搭建mybatis源码运行的环境
|
3月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
3月前
|
供应链 前端开发 Java
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】
该博客文章介绍了一个使用Mybatis、Layui、MVC和JSP技术栈开发的服装库存管理系统,包括注册登录、权限管理、用户和货号管理、库存管理等功能,并提供了源码下载链接。
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】
|
3月前
|
缓存 Java 数据库连接
我要手撕mybatis源码
该文章深入分析了MyBatis框架的初始化和数据读写阶段的源码,详细阐述了MyBatis如何通过配置文件解析、建立数据库连接、映射接口绑定、动态代理、查询缓存和结果集处理等步骤实现ORM功能,以及与传统JDBC编程相比的优势。
我要手撕mybatis源码
|
5月前
|
SQL 缓存 Java
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
Java框架之MyBatis 07-动态SQL-缓存机制-逆向工程-分页插件
下一篇
无影云桌面