开发者社区> 游客tqcqp5pa4cdy4> 正文

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

简介: 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);
      }
    }
  }


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
如何设置阿里云服务器安全组?阿里云安全组规则详细解说
阿里云安全组设置详细图文教程(收藏起来) 阿里云服务器安全组设置规则分享,阿里云服务器安全组如何放行端口设置教程。阿里云会要求客户设置安全组,如果不设置,阿里云会指定默认的安全组。那么,这个安全组是什么呢?顾名思义,就是为了服务器安全设置的。安全组其实就是一个虚拟的防火墙,可以让用户从端口、IP的维度来筛选对应服务器的访问者,从而形成一个云上的安全域。
18582 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,阿里云优惠总结大概有三种登录方式: 登录到ECS云服务器控制台 在ECS云服务器控制台用户可以更改密码、更换系.
27728 0
阿里云服务器如何登录?阿里云服务器的三种登录方法
购买阿里云ECS云服务器后如何登录?场景不同,大概有三种登录方式:
12968 0
阿里云服务器安全组设置内网互通的方法
虽然0.0.0.0/0使用非常方便,但是发现很多同学使用它来做内网互通,这是有安全风险的,实例有可能会在经典网络被内网IP访问到。下面介绍一下四种安全的内网互联设置方法。 购买前请先:领取阿里云幸运券,有很多优惠,可到下文中领取。
21935 0
阿里云服务器ECS登录用户名是什么?系统不同默认账号也不同
阿里云服务器Windows系统默认用户名administrator,Linux镜像服务器用户名root
15292 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
19980 0
腾讯云服务器 设置ngxin + fastdfs +tomcat 开机自启动
在tomcat中新建一个可以启动的 .sh 脚本文件 /usr/local/tomcat7/bin/ export JAVA_HOME=/usr/local/java/jdk7 export PATH=$JAVA_HOME/bin/:$PATH export CLASSPATH=.
14855 0
84
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
JS零基础入门教程(上册)
立即下载
性能优化方法论
立即下载
手把手学习日志服务SLS,云启实验室实战指南
立即下载