Mybatis源码系列1-Mybaits初始化(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Mybatis源码系列1-Mybaits初始化(上)

人非要经历一番不同平时的劫难才能脱胎换骨,成为真正能解决问题的人

简介初始化过程1.解析XML配置文件1.1 Config文件的解析1.2 Mapper文件的解析1.2.1 解析CURD模板1.2.2 绑定Mapper到命名空间2.创建SqlSessionFactory总结


简介


首先我们再回顾下Mybaits的基本使用。

//加载配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//SqlSession 的获取
SqlSession sqlSession = sqlSessionFactory.openSession();
try{
//执行sql
User user = sqlSession.selectOne("MyMapper.selectUser", 1);//(SQL通过命名空间+SQLID 的格式定位)
}finally {
sqlSession .close();
}

一切都从SqlSessionFactoryBuilder说起。SqlSessionFactoryBuilder是通过builder设计模式来创建一个SqlSessionFactory 工厂。


创建SqlSessionFactory  最主要分为两步,


public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
    try {
      // 1.xml配置文件解析器。
      XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
      Configuration config = parser.parse()
      // 2.根据解析到的配置,创建DefaultSqlSessionFactory 
      return build(config);
  }
  //创建默认的sqlsesion工厂。
public SqlSessionFactory build(Configuration config) {
    return new DefaultSqlSessionFactory(config);
}


初始化过程


1.解析XML配置文件

SqlSessionFactoryBuilder的第一步就是配置的解析。

配置文件主要分为两种:

  • Conifg文件: 包括数据连接配置,全局设置配置。
  • Mapper文件:用于SQL的统一管理,对SQL的配置。


image.png


1.1 Config文件的解析

Config文件的解析是由XMLConfigBuilder做的。

private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
    super(new Configuration());//创建一个Configuration对象
    ErrorContext.instance().resource("SQL Mapper Configuration");
    this.configuration.setVariables(props);
    this.parsed = false;
    this.environment = environment;
    this.parser = parser;
  }

我们来看看parse()方法

public Configuration parse() {
    parsed = true;
    //从根节点开始解析
    parseConfiguration(parser.evalNode("/configuration"));
    return configuration;
  }
  private void parseConfiguration(XNode root) {
    try {
      // 解析 properties配置
      propertiesElement(root.evalNode("properties"));
      // 解析 settings配置
      Properties settings = settingsAsProperties(root.evalNode("settings"));
      loadCustomVfs(settings);
      typeAliasesElement(root.evalNode("typeAliases"));
      pluginElement(root.evalNode("plugins"));
      objectFactoryElement(root.evalNode("objectFactory"));
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
      reflectorFactoryElement(root.evalNode("reflectorFactory"));
      settingsElement(settings);
      //解析environment  配置
      environmentsElement(root.evalNode("environments"));
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
      typeHandlerElement(root.evalNode("typeHandlers"));
      // 解析 mapper 配置
      mapperElement(root.evalNode("mappers"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
    }
  }

XMLConfigBuilder 根据约定,解析config 配置文件中的各个标签。并将相关配置信息放到Configuration 对象中返回。

列如:

Properties settings = settingsAsProperties(root.evalNode("settings"));//解析settings标签
settingsElement(settings);//设置settings配置到configuration 对象。


1.2 Mapper文件的解析

在解析Config配置文件过程中,会伴随Mapper.xml文件的解析。这个解析的工作是由XMLMapperBuilder 完成的。

config中的mapper文件位置配置

<mappers>
    <mapper resource="mappers/UserMapper.xml"/>
</mappers>


Mapper.xml


<mapper namespace="com.wqd.dao.UserMapper">
   <select id="selectUser" resultType="com.wqd.model.User">
      select * from user where id= #{id}
   </select>
</mapper>


XMLMapperBuilder


public void parse() {
    if (!configuration.isResourceLoaded(resource)) {
        //1.从根标签mapper开始解析mapper文件
      configurationElement(parser.evalNode("/mapper"));
      configuration.addLoadedResource(resource);
      //2.绑定mapper到命名空间
      bindMapperForNamespace();
    }
    parsePendingResultMaps();
    parsePendingCacheRefs();
    parsePendingStatements();
  }
//1.解析mapper文件
private void configurationElement(XNode context) {
    try {
    //命名空间必须要有
      String namespace = context.getStringAttribute("namespace");
      if (namespace == null || namespace.equals("")) {
        throw new BuilderException("Mapper's namespace cannot be empty");
      }
      builderAssistant.setCurrentNamespace(namespace);
      //缓存的相关设置
      cacheRefElement(context.evalNode("cache-ref"));
      cacheElement(context.evalNode("cache"));
      //参数类型解析
      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
      //结果集类型解析
      resultMapElements(context.evalNodes("/mapper/resultMap"));
      //解析sql标签配置的sql 片段
      sqlElement(context.evalNodes("/mapper/sql"));
       //解析select|insert|update|delete 标签配置的sql 模板(重点)  
     buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }
//2.绑定命名空间
private void bindMapperForNamespace() {
    String namespace = builderAssistant.getCurrentNamespace();
    if (namespace != null) {
      Class<?> boundType = null;
      try {
        boundType = Resources.classForName(namespace);
      } catch (ClassNotFoundException e) {
      }
      if (boundType != null) {//如果有对应的Class
        if (!configuration.hasMapper(boundType)) {
          configuration.addLoadedResource("namespace:" + namespace);
          configuration.addMapper(boundType);//添加到缓存
        }
      }
    }
  }

这里我们重点讲讲XMLMapperBuilder 中有两个重要的点


1.2.1 解析CURD模板

也就是解析select|insert|update|delete代表的SQL 模板。这四种标签配置的SQL模板是我们操作数据库时的SQL执行语句的模板。 我们可以理解为:一个select 标签表示一类动态SQL。

buildStatementFromContext(context.evalNodes("select|insert|update|delete"));


每一个select|insert|update|delete由XMLStatementBuilder 解析


private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
    for (XNode context : list) {
       //解析"select|insert|update|delete"标签
      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
      try {
        statementParser.parseStatementNode();
      } catch (IncompleteElementException e) {
        configuration.addIncompleteStatement(statementParser);
      }
    }
  }


相关文章
|
1月前
|
XML Java 数据库连接
mybatis源码研究、搭建mybatis源码运行的环境
这篇文章详细介绍了如何搭建MyBatis源码运行的环境,包括创建Maven项目、导入源码、添加代码、Debug运行研究源码,并提供了解决常见问题的方法和链接到搭建好的环境。
mybatis源码研究、搭建mybatis源码运行的环境
|
1月前
|
Web App开发 前端开发 关系型数据库
基于SpringBoot+Vue+Redis+Mybatis的商城购物系统 【系统实现+系统源码+答辩PPT】
这篇文章介绍了一个基于SpringBoot+Vue+Redis+Mybatis技术栈开发的商城购物系统,包括系统功能、页面展示、前后端项目结构和核心代码,以及如何获取系统源码和答辩PPT的方法。
|
1月前
|
供应链 前端开发 Java
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】
该博客文章介绍了一个使用Mybatis、Layui、MVC和JSP技术栈开发的服装库存管理系统,包括注册登录、权限管理、用户和货号管理、库存管理等功能,并提供了源码下载链接。
服装库存管理系统 Mybatis+Layui+MVC+JSP【完整功能介绍+实现详情+源码】
|
1月前
|
缓存 Java 数据库连接
我要手撕mybatis源码
该文章深入分析了MyBatis框架的初始化和数据读写阶段的源码,详细阐述了MyBatis如何通过配置文件解析、建立数据库连接、映射接口绑定、动态代理、查询缓存和结果集处理等步骤实现ORM功能,以及与传统JDBC编程相比的优势。
我要手撕mybatis源码
|
4月前
|
SQL XML Java
MyBatis初探:揭示初始化阶段的核心流程与内部机制
MyBatis初探:揭示初始化阶段的核心流程与内部机制
50 2
MyBatis初探:揭示初始化阶段的核心流程与内部机制
|
4月前
|
SQL Java 数据库连接
深入源码:解密MyBatis数据源设计的精妙机制
深入源码:解密MyBatis数据源设计的精妙机制
77 1
深入源码:解密MyBatis数据源设计的精妙机制
|
4月前
|
SQL 缓存 Java
|
4月前
|
XML Java 数据库连接
探秘MyBatis:手写Mapper代理的源码解析与实现
探秘MyBatis:手写Mapper代理的源码解析与实现
43 1
|
4月前
|
SQL Java 数据库连接
一文细说Mybatis八大核心源码
以上 是V哥给大家整理的8大核心组件的全部内容,为什么说选择 Java 就是选择未来,真正爱 Java 的人,一定喜欢深入研究,学习源码只是第一步,要有一杆子捅到操作系统才够刺激。
|
4月前
|
Java 数据库连接 mybatis
mybatis简单案例源码详细【注释全面】——Utils层(MybatisUtils.java)
mybatis简单案例源码详细【注释全面】——Utils层(MybatisUtils.java)