Mybatis3.2源码分析:
一、加载配置文件。
    使用SAX解析配置文件。读取xml配置文件后,调用XMLConfigBuilder.parse()方法,在parse方法中再调用parseConfiguration()方法,对读取到的配置信息保存到BaseBuilder.configuration中。
     propertiesElement(root.evalNode("properties")); //issue #117 read properties first    
        代码分析:此方法实现将属性信息存入Configuration中。
            1、如果properties节点不为空,查找配置节点中子节点的属性文件并赋值给defaults(Properties类型,继承自HashTable,线程安全的,HashTable集成Dictionary,实现Map接口),否则此方法结束。
            2、查询resource和url,注意两者不能同时配置,否则会抛出异常,最后将resource或url的属性putAll 进入 defaults中,
            3、将defaults变量存入Configuration中去。
      typeAliasesElement(root.evalNode("typeAliases"));
        代码分析:此方法实现将Bean的别名保存在BaseBuilder.typeAliasRegistry中,如果别名为空,则存Bean的SimpleName。
           
      pluginElement(root.evalNode("plugins"));
        代码分析:此方法将插件信息存入configuration中,可以配置属性。configuration.interceptors
      objectFactoryElement(root.evalNode("objectFactory"));
        代码分析:对象工厂,如果为空则默认使用DefaultObjectFactory工厂。configuration.objectFactory
      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
         代码分析:对象包装工厂,如果为空则默认使用DefaultObjectWrapperFactory。configuration.objectWrapperFactory
      settingsElement(root.evalNode("settings"));
         代码分析:先获取settings节点子节点properties属性解析到Properties props中,检查是否由不存在的setter方法,有则抛出异常。没有问题则将pros的值赋值到configuration中去,如果pros中的值为空,则设置一个默认值。
                           详细如下:
                                    configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior",
"PARTIAL")));
      configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
      configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
      configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
      configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
      configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
      configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
      configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
      configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
      configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
      configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
      configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
      configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
      configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
      configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
      configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
      configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
      configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
      configuration.setLogPrefix(props.getProperty("logPrefix"));
      configuration.setLogImpl(resolveClass(props.getProperty("logImpl")));
      configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
      environmentsElement(root.evalNode("environments")); // read it after objectFactory and objectWrapperFactory
issue #631
         代码分析:设置运行环境。如果为空,默认使用default。如果设置指定的环境id,则设置事务工厂,设置数据源。并build环境。id,transactionFactory,dataSource都不允许为空。configuration.setEnvironment
      databaseIdProviderElement(root.evalNode("databaseIdProvider"));
         代码分析:获取数据库产品的名称。dataSource为空会抛出异常。注:如果使用多个数据源就需要采用多个SqlSessionFactory的配置,为不同的调用使用不同的SqlSessionFactory,在mybatis中自己是无法实现的,需要使用spring托管数据源方可。
      typeHandlerElement(root.evalNode("typeHandlers"));
         代码分析:自定义数据类型转换。提供javaType和jdbcType的映射。BaseBuilder.typeHandlerRegistry。
      mapperElement(root.evalNode("mappers"));
        代码分析:如果子节点是package,获取package的name。调用configuration.addMappers(mapperPackage);这个方法的内部调用mapperRegistry.addMappers(packageName);在这个方法中根据包名搜索下面的类并添加到knownMappers中,knownMappers是在MapperRegistry中定义的一个final
map。mapper.resource使用xml资源文件。mapper.url可以使用绝对地址,理论上讲可以从网络上直接调用地址,可以在远程服务器上传一个xml拿下来解析。mapper.class使用注解方式的时候使用这种方式。
        resource和url两种配置方式都调用了XMLMapperBuilder.parse()方法,解析加载到的mapper文件,调用mapperRegistry.addMapper(Class<T> type)方法。然后移除挂起的ResultMap,挂起的缓存引用,挂起的Statement。
        通过configuration都可以获取这些mapper信息。
    
        在mapperParser.parse().configurationElement():
            
            private void configurationElement(XNode context) {
    try {
      String namespace = context.getStringAttribute("namespace");
      if (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"));
      sqlElement(context.evalNodes("/mapper/sql"));
      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
    } catch (Exception e) {
      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
    }
  }
            在这里解析了mapper文件,将
二、创建SqlSessionFactory。
        在第一步加载配置问价您的时候创建了一个configuration对象,将这个对象传入SqlSessionFactoryBuilder,创建一个DefaultSqlSessionFactory的工厂对象。

三、创建SqlSession:

        SqlSession由SqlSessionFactory创建,SqlSessionFactory提供了8种openSession多态方法,不带参数的自动提交为false,SqlSessionFactory还提供一个获取configuration的方法,调用openSession方法获取到一个DefaultSqlSession。
四、获取到Mapper代理:
        使用SqlSession.getMapper(XXXMapper.class)获取代理类,实际获取位置是MapperRegistry.knownMappers。获取到指定接口的MapperProxyFactory,然后MapperProxyFactory.newInstance(sqlSession);(这里使用了动态代理)这样就生成了一个XXXMapper的代理类,返回。
        
五、接口方法调用:
        当调用接口方法的时候,实际上调用的MapperProxy这个类的实例对象中的invoke方法,在invoke方法中使用了方法缓存,最后调用mapperMethod.execute方法。
        下面分析SqlSession.selectOne():这个方法最终会调用到:public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds),其中的executor根据是否开启缓存来选择,如果开启缓存:则使用CacheingExecutor.query,如果没有再调用BaseExecutor.query查询结果,并将查询出来的结果存放到CachingExecutor中的tcm(TransactionalCacheManager)对象中,TransactionalCacheManager内部使用了HashMap存储缓存和事务缓存。接着我们看BaseExecutor.query的调用,
它最终调用到:
        private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql);
        BaseExecutor : protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql);
        SimpleExecutor : public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException;
        经过一系列中转,最终调用到jdbc预编译,和执行,之后按照要求组装查询到的数据。
            
六、在Mybatis中使用了的设计模式:
1、动态代理,最典型的是通过动态代理委托MapperProxy执行相关数据操作。
2、装饰器模式:开启缓存的时候,Caching包装了SimpleExecutor;对象工厂装饰器objectFactoryWrapper。
3、工厂模式:SqlSessionFactory的使用,还有MapperProxyFactory。
4、构造器模式:构建Configuration对象的步骤。
使用Mybatis相关:
5、SqlSessionFactory无需重复创建,在使用时应该使用单例模式调用。
 

MyBatis 3源码分析的更多相关文章

  1. 深度 Mybatis 3 源码分析(一)SqlSessionFactoryBuilder源码分析

    MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装.MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java ...

  2. mybatis缓存源码分析之浅谈缓存设计

    本文是关于mybatis缓存模块设计的读后感,关于缓存的思考,关于mybatis的缓存源码详细分析在另一篇文章:https://www.cnblogs.com/gmt-hao/p/12448896.h ...

  3. mybatis底层源码分析之--配置文件读取和解析

    现在企业级开发中ssm是很常见的技术标配,mybatis比hibernate轻量了很多,而且学习成本相对较低,简单易上手. 那么,问题来了,简单好用的mybatis底层到底是如何实现的呢?都使用了什么 ...

  4. spring 框架整合mybatis的源码分析

    问题:spring 在整合mybatis的时候,我们是看不见sqlSessionFactory,和sqlsession(sqlsessionTemplate 就是sqlsession的具体实现)的,这 ...

  5. MyBatis 事务源码分析

    先来看看在JAVA事务的相关技术,在JAVA中有两类事务,JDBC事务和JTA事务,如果是JDBC类型的事务,则是由Connection类来控制的.如果创建一个Connection对象时,没有显示调用 ...

  6. Mybatis底层源码分析

    MyBatis 流程图 Configuration.xml 该配置文件是 MyBatis 的全局配置文件,在这个文件中可以配置诸多项目.常用的内容是别名设置,拦截器设置等. Properties(属性 ...

  7. MyBatis源码分析(1)-MapConfig文件的解析

    1.简述 MyBatis是一个优秀的轻ORM框架,由最初的iBatis演化而来,可以方便的完成sql语句的输入输出到java对象之间的相互映射,典型的MyBatis使用的方式如下: String re ...

  8. 【MyBatis】MyBatis Tomcat JNDI原理及源码分析

    一. Tomcat JNDI JNDI(java nameing and drectory interface),是一组在Java应用中访问命名和服务的API,所谓命名服务,即将对象和名称联系起来,使 ...

  9. MyBatis源码分析-MyBatis初始化流程

    MyBatis 是支持定制化 SQL.存储过程以及高级映射的优秀的持久层框架.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis 可以对配置和原生Map使用简 ...

随机推荐

  1. 变量监控 指令 gt-wach

    index8.html <html><head> <title>变量监控指令 gt-watch</title> <script src=" ...

  2. 回归到最初的编程——Linux下的C编程

    最近感觉有些浮躁,一方面感觉最近写公司的PHP代码倍感无聊,没有什么成就感!另一方面面对我的mac电脑中安装了诸多开发语言,倍感浮躁与困惑!同时想到这么多年来,却一直在使用PHP进行程序开发,总觉得有 ...

  3. C#基础知识系列六(静态类和静态类成员)

    静态类 静态类与非静态类基本相同,但存在一个区别:静态类不能实例化. 也就是说,不能使用 new 关键字创建静态类类型的变量. 因为没有实例变量,所以要使用类名本身访问静态类的成员. 例如,如果名为 ...

  4. 项目笔记---Socket Error Code翻译

    前言 在项目中为了方便调试及客户反馈,需要Socket错误数字的中文解释,MSDN上只有英文版,同时也想自己学习而且方便将来更新ErrorCode的实际发生的情景,顾有此博文. MSDN:https: ...

  5. 并行程序设计模式--Master-Worker模式

    简介 Master-Worker模式是常用的并行设计模式.它的核心思想是,系统有两个进程协议工作:Master进程和Worker进程.Master进程负责接收和分配任务,Worker进程负责处理子任务 ...

  6. iOS不得姐项目--推荐关注模块(一个控制器控制两个tableView),数据重复请求的问题,分页数据的加载,上拉下拉刷新(MJRefresh)

    一.推荐关注模块(一个控制器控制两个tableView) -- 数据的显示 刚开始加载数据值得注意的有以下几点 导航控制器会自动调整scrollView的contentInset,最好是取消系统的设置 ...

  7. NOIP 2014 Day1 T3飞扬的小鸟

    题目描述:http://codevs.cn/problem/3729/ 表示各种shabi的我编和调了半天,思路大体就是一个完全背包的模型,不过会多一些额外的转移(因为题目限制高度之类的),不过值得注 ...

  8. Matlab最短路径问题记录

    利用graphshortestpath 可以求最短路径,具体用法参考MATLAB帮助 S=[1 1 2 2 3 3 4 4 4 4 5 6 6 7 8]; %起始节点向量 E=[2 3 5 4 4 6 ...

  9. HDU 5497 Inversion

    Time Limit: 3000MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description You have ...

  10. POJ2135 Farm Tour

      Farm Tour Time Limit: 2MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Description ...