1,mybatis流程跟踪,原理理解

基本思路: 从SqlSessionFactory的初始化出发,观察资源的准备和环境的准备,以及实现持久层的一些过程;

进入SqlSessionFactoryBean类,发现先执行的是

然后是:

在初始化类之后,做的准备工作如下:

public void afterPropertiesSet() throws Exception {
    notNull(dataSource, "Property 'dataSource' is required");//1,检查spring准备的datasource是否ok
    notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");//2,检查空构造方法的sqlSessionFactoryBuilder是否准备好

this.sqlSessionFactory = buildSqlSessionFactory();//3,利用配置的属性,构造sqlSessionFactory
  }

构造细节如下:方法有点长,注意注释这个是流程,之后我画一个图来加深理解;

protected SqlSessionFactory buildSqlSessionFactory() throws IOException {

Configuration configuration;

XMLConfigBuilder xmlConfigBuilder = null;
   if (this.configLocation != null) {//1,检查是否有配置configLocation,即mybatis的整体配置文件,非mapper文件,如果有加载进去,没有,构造一个空的
     xmlConfigBuilder = new XMLConfigBuilder(this.configLocation.getInputStream(), null, this.configurationProperties);
     configuration = xmlConfigBuilder.getConfiguration();
   } else {
     if (logger.isDebugEnabled()) {
       logger.debug("Property 'configLocation' not specified, using default MyBatis Configuration");
     }
     configuration = new Configuration();
     configuration.setVariables(this.configurationProperties);
   }

if (this.objectFactory != null) {//2,检查对象工厂,如果有设置进去,没有留空
     configuration.setObjectFactory(this.objectFactory);
   }

if (this.objectWrapperFactory != null) {//3,检查对象装饰工厂,如果有设置进去,没有留空

configuration.setObjectWrapperFactory(this.objectWrapperFactory);
   }

if (hasLength(this.typeAliasesPackage)) {//4,检查包的简称,如果有注册进去
     String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
     for (String packageToScan : typeAliasPackageArray) {
       configuration.getTypeAliasRegistry().registerAliases(packageToScan,
               typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
       if (logger.isDebugEnabled()) {
         logger.debug("Scanned package: '" + packageToScan + "' for aliases");
       }
     }
   }

if (!isEmpty(this.typeAliases)) {//5,检查类的简称,如果有注册进去
     for (Class<?> typeAlias : this.typeAliases) {
       configuration.getTypeAliasRegistry().registerAlias(typeAlias);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered type alias: '" + typeAlias + "'");
       }
     }
   }

if (!isEmpty(this.plugins)) {//6,检查插件,如果有注册进去
     for (Interceptor plugin : this.plugins) {
       configuration.addInterceptor(plugin);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered plugin: '" + plugin + "'");
       }
     }
   }

if (hasLength(this.typeHandlersPackage)) {//7,检查类型转换类包,如果有注册进去
     String[] typeHandlersPackageArray = tokenizeToStringArray(this.typeHandlersPackage,
         ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
     for (String packageToScan : typeHandlersPackageArray) {
       configuration.getTypeHandlerRegistry().register(packageToScan);
       if (logger.isDebugEnabled()) {
         logger.debug("Scanned package: '" + packageToScan + "' for type handlers");
       }
     }
   }

if (!isEmpty(this.typeHandlers)) {//8,检查类型转换类,如果有注册进去
     for (TypeHandler<?> typeHandler : this.typeHandlers) {
       configuration.getTypeHandlerRegistry().register(typeHandler);
       if (logger.isDebugEnabled()) {
         logger.debug("Registered type handler: '" + typeHandler + "'");
       }
     }
   }

if (xmlConfigBuilder != null) {//9,检查是否有xml的构造器,如果有,直接使用构造器构造
     try {
       xmlConfigBuilder.parse();

if (logger.isDebugEnabled()) {
         logger.debug("Parsed configuration file: '" + this.configLocation + "'");
       }
     } catch (Exception ex) {
       throw new NestedIOException("Failed to parse config resource: " + this.configLocation, ex);
     } finally {
       ErrorContext.instance().reset();
     }
   }

if (this.transactionFactory == null) {//10,检查事物工厂,如果没有,构造一个spring管理的事物工厂
     this.transactionFactory = new SpringManagedTransactionFactory();
   }

//11,构造环境变量

Environment environment = new Environment(this.environment, this.transactionFactory, this.dataSource);
   configuration.setEnvironment(environment);

if (this.databaseIdProvider != null) {
     try {//12,检查是否配置了db id,如果有,设置到配置的类中
       configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
     } catch (SQLException e) {
       throw new NestedIOException("Failed getting a databaseId", e);
     }
   }

if (!isEmpty(this.mapperLocations)) {//13,把配置的mapper弄进来总配置文件里
     for (Resource mapperLocation : this.mapperLocations) {
       if (mapperLocation == null) {
         continue;
       }

try {
         XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
             configuration, mapperLocation.toString(), configuration.getSqlFragments());
         xmlMapperBuilder.parse();
       } catch (Exception e) {
         throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e);
       } finally {
         ErrorContext.instance().reset();
       }

if (logger.isDebugEnabled()) {
         logger.debug("Parsed mapper file: '" + mapperLocation + "'");
       }
     }
   } else {
     if (logger.isDebugEnabled()) {
       logger.debug("Property 'mapperLocations' was not specified or no matching resources found");
     }
   }

return this.sqlSessionFactoryBuilder.build(configuration);//14,最后通过得到的配置类来构造一个sqlsessionFactory工厂
}

设置好属性之后,执行

得到factory构造的bean,即sqlSessionFactory,

最后容器启动成功的事件监控

public void onApplicationEvent(ApplicationEvent event) {
   if (failFast && event instanceof ContextRefreshedEvent) {
     // fail-fast -> check all statements are completed
     this.sqlSessionFactory.getConfiguration().getMappedStatementNames();
   }
}

以上是资源的准备,下面来一次增删改查的跟踪,观察内部的工作原理;

查询单条记录的过程:

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
  try {
    MappedStatement ms = configuration.getMappedStatement(statement);//1,通过转换,得到存储的mapperedStatement
    List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);//2,转换成jdbc代码执行
    return result;
  } catch (Exception e) {
    throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
  } finally {
    ErrorContext.instance().reset();
  }
}

内部就像是一台精密的仪器,去除了大量的模版jdbc代码;

mybatis笔记3 一些原理的理解的更多相关文章

  1. Mybatis笔记01-基本原理,配置文件,映射文件,以及调用过程

    Mybatis基本原理 应用程序找Mybatis要数据 mybatis从数据库中找来数据 2.1 通过mybatis-config.xml 定位哪个数据库 2.2 通过Category.xml执行对应 ...

  2. Python源代码剖析笔记3-Python运行原理初探

    Python源代码剖析笔记3-Python执行原理初探 本文简书地址:http://www.jianshu.com/p/03af86845c95 之前写了几篇源代码剖析笔记,然而慢慢觉得没有从一个宏观 ...

  3. 动态代理之投鞭断流!看一下MyBatis的底层实现原理

    转:https://mp.weixin.qq.com/s?__biz=MzI1NDQ3MjQxNA==&mid=2247486856&idx=1&sn=d430be5d14d1 ...

  4. MyBatis笔记二:配置

    MyBatis笔记二:配置 1.全局配置 1.properites 这个配置主要是引入我们的 properites 配置文件的: <properties resource="db.pr ...

  5. Atitit 泛型原理与理解attilax总结

    Atitit 泛型原理与理解attilax总结 1. 泛型历史11.1.1. 由来11.2. 为什么需要泛型,类型安全21.3. 7.泛型的好处22. 泛型的机制编辑22.1.1. 机制32.1.2. ...

  6. 从tcp原理角度理解Broken pipe和Connection reset by peer的区别

    从tcp原理角度理解Broken pipe和Connection reset by peer的区别 http://lovestblog.cn/blog/2014/05/20/tcp-broken-pi ...

  7. C++标准库第二版笔记 3 和异常的理解 1

    C++标准库第二版笔记 3 和异常的理解 1 差错和异常(error and exception)的处理 标准异常类(exception class) 定义于 分为: 1.语言本身支持的异常 2.标准 ...

  8. Mybatis笔记二:接口式编程

    目录 旧方法的弊端 接口式编程 接口式编程的好处 接口式编程的增删改查 旧方法的弊端 在Mybatis笔记一中,我们使用命名空间+id的方式实现了Mybatis的执行,不过这里的命名空间是我们随便写的 ...

  9. 对CAP原理的理解

    对CAP原理的理解 CAP原理按照定义,指的是C(Consistency)一致性,A(Availability)可用性,P(Partition tolerance)分区容错性在一个完整的计算机系统中三 ...

随机推荐

  1. ES6的一些常用特性

    由于公司的前端业务全部基于ES6开发,于是给自己开个小灶补补ES6的一些常用特性.原来打算花两天学习ES6的,结果花了3天才勉强过了一遍阮老师的ES6标准入门(水好深,ES6没学好ES7又来了...) ...

  2. Java消息队列--JMS概述

    1.什么是JMS JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送 ...

  3. [开发笔记] Graph Databases on developing

    TimeWall is a graph databases github It be used to apply mathematic model and social network with gr ...

  4. Python多线程爬虫爬取电影天堂资源

    最近花些时间学习了一下Python,并写了一个多线程的爬虫程序来获取电影天堂上资源的迅雷下载地址,代码已经上传到GitHub上了,需要的同学可以自行下载.刚开始学习python希望可以获得宝贵的意见. ...

  5. AbpZero--1.如何开始

    1.加群 群号:104390185,下载这个文件并解压 用VS2015打开aspnet-zero-1.9.0.1 2.修改Web项目web.config连接字符串 <add name=" ...

  6. C# 数组的交集、差集、并集

    C# 数组的交集.差集.并集 工作中经常会用这方面的知识来检查那些字段是必须输入的,那些是禁止输入. using System; using System.Collections.Generic; u ...

  7. JAVA构造时成员初始化的陷阱

    让我们先来看两个类:Base和Derived类.注意其中的whenAmISet成员变量,和方法preProcess(). 情景1:(子类无构造方法) class Base { Base() { pre ...

  8. 【深入Java虚拟机】之四:类加载机制

    类加载过程     类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载.验证.准备.解析.初始化.使用和卸载七个阶段.它们开始的顺序如下图所示: 其中类加载的过程包括了加载.验 ...

  9. 端盘子的服务生到月薪一万五的IT精英,你能相信吗

    一直以来,我都觉得自己不是一个有故事的人. 以前的我,是个乖宝宝,对父母言听计从,特别内向,甚至一度感觉到自卑.不上学之后,我干过送货员,去工地除泥搬砖,当过油漆工,去过工厂,还去饭店当过端盘子的服务 ...

  10. 一步步开发自己的博客 .NET版(1、基本显示)

    前言 我们每个猿都有一个搭建自己独立博客的梦,我也不例外.以前想 现在想 以后也想.之所以一直迟迟没有着手,是因为难以跨出第一步.每次心里想着,等我以后技术好了再说,然后就没有然后了.以前用过word ...