在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到

  代码:XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);

  使用读取的configuration.xml字符输入流作为参数,使用XMLConfigBuilder类的三个参数的构造器实例化一个xml配置解析器(XMLConfigBuilder),并且 environment, properties的值为null。并且在这个过程中会实例化一个非常重要的类Configuration的对象。那么接下来就看一下XMLConfigBuilder的实例化过程

一,首先看下这个三个参数的构造器源码:

  

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

这里又通过this关键字,调用了XMLConfigBuilder类的另外一个三个参数的私有构造方法:

  这个构造器的参数XPathParser parser就等于上一个构造器中的new XPathParser(reader, true, props, new XMLMapperEntityResolver());

  XPathParser 是一个xml解析器,同时reader就是configuration.xml字符输入流,而props等于null;

    具体的XPathParser xml解析器的实例化过程就不再这里详细描述了,大家有需要,我再领写一篇文章。

  同时environment, properties的值为null

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

在这个构造器中类XMLConfigBuilder使用super关键字调用了父类BaseBuilder的使用Configuration作为参数的构造方法:

  

public class XMLConfigBuilder extends BaseBuilder
  public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}

二,Configuration 的初始化

  从第一步我们知道,类XMLConfigBuilder使用super关键字调用了父类BaseBuilder的使用Configuration作为参数的构造方法。

  代码:super(new Configuration());

  这里new Configuration()实例化了一个实例,并且类Configuration就是上文提到的非常重要的类。首先来浏览一下Configuration类的大致结构。

  

public class Configuration {

  protected Environment environment;

  ......

  protected Properties variables = new Properties();

  ......
//类型别名注册表
protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
//语言驱动注册表
protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry(); ...... public Configuration(Environment environment) {
this();
this.environment = environment;
} public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); typeAliasRegistry.registerAlias("JNDI", JndiDataSourceFactory.class);
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
typeAliasRegistry.registerAlias("UNPOOLED", UnpooledDataSourceFactory.class); typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);
typeAliasRegistry.registerAlias("FIFO", FifoCache.class);
typeAliasRegistry.registerAlias("LRU", LruCache.class);
typeAliasRegistry.registerAlias("SOFT", SoftCache.class);
typeAliasRegistry.registerAlias("WEAK", WeakCache.class); typeAliasRegistry.registerAlias("DB_VENDOR", VendorDatabaseIdProvider.class); typeAliasRegistry.registerAlias("XML", XMLLanguageDriver.class);
typeAliasRegistry.registerAlias("RAW", RawLanguageDriver.class); typeAliasRegistry.registerAlias("SLF4J", Slf4jImpl.class);
typeAliasRegistry.registerAlias("COMMONS_LOGGING", JakartaCommonsLoggingImpl.class);
typeAliasRegistry.registerAlias("LOG4J", Log4jImpl.class);
typeAliasRegistry.registerAlias("LOG4J2", Log4j2Impl.class);
typeAliasRegistry.registerAlias("JDK_LOGGING", Jdk14LoggingImpl.class);
typeAliasRegistry.registerAlias("STDOUT_LOGGING", StdOutImpl.class);
typeAliasRegistry.registerAlias("NO_LOGGING", NoLoggingImpl.class); typeAliasRegistry.registerAlias("CGLIB", CglibProxyFactory.class);
typeAliasRegistry.registerAlias("JAVASSIST", JavassistProxyFactory.class); languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
languageRegistry.register(RawLanguageDriver.class);
} }

  诚然,这个类被我简化了,忽略了一些其他的属性和方法,当然这些被忽略的属性和方法中,也包含重要的属性和方法,这些重要的属性和方法将在后续的文章中逐一说明。

  1,首先看一个类TypeAliasRegistry (类型别名注册表),其实这个类封装了一个HashMap,键为类的别名,值为类对象。看一下简化的源码:

    

public class TypeAliasRegistry {

  private final Map<String, Class<?>> TYPE_ALIASES = new HashMap<String, Class<?>>();

  public TypeAliasRegistry() {
registerAlias("string", String.class); registerAlias("byte", Byte.class);
registerAlias("long", Long.class);
registerAlias("short", Short.class);
registerAlias("int", Integer.class);
registerAlias("integer", Integer.class);
registerAlias("double", Double.class);
registerAlias("float", Float.class);
registerAlias("boolean", Boolean.class); ......
} @SuppressWarnings("unchecked")
// 获取类对象
public <T> Class<T> resolveAlias(String string) {
try {
if (string == null) return null;
String key = string.toLowerCase(Locale.ENGLISH); // issue #748
Class<T> value;
if (TYPE_ALIASES.containsKey(key)) {
value = (Class<T>) TYPE_ALIASES.get(key);
} else {
value = (Class<T>) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
} .....
//保存类对象
public void registerAlias(String alias, Class<?> value) {
if (alias == null) throw new TypeException("The parameter alias cannot be null");
String key = alias.toLowerCase(Locale.ENGLISH); // issue #748
if (TYPE_ALIASES.containsKey(key) && TYPE_ALIASES.get(key) != null && !TYPE_ALIASES.get(key).equals(value)) {
throw new TypeException("The alias '" + alias + "' is already mapped to the value '" + TYPE_ALIASES.get(key).getName() + "'.");
}
TYPE_ALIASES.put(key, value);
} ...... }

    1,TypeAliasRegistry类中有一个final 修饰的TYPE_ALIASES  HashMao,Map中以别名-类对象的键-值对保存别名和类对象。

    2,TypeAliasRegistry类中有一个保存别名-类对象的方法registerAlias,参数正式String  类型的别名和Class 类型的类对象,在这个方法中首先检查Map TYPE_ALIASES中是否已经存在,如果存在就会抛出TypeException异常。如果不存在就将别名-类对象保存到Map TYPE_ALIASES中。另外一个方法resolveAlias是根据别名获取类对象或者使用类加载器加载一个类返回类对象。

    3,TypeAliasRegistry类中还有一个构造方法,在这个构造方法中,对常用的类对象和别名调用registerAlias方法,进行了初始化。

  2,了解了TypeAliasRegistry中的内容后,就该回头看看Configuration 类的构造方法了。

    

public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
typeAliasRegistry.registerAlias("MANAGED", ManagedTransactionFactory.class); .....
}

  显而易见,在Configuration类的构造方法中,也向TypeAliasRegistry(类型别名注册表)中添加了一些别名和类对象。

  3,除去了解了Configuration类的构造方法都做了什么事情外,还要知道

    protected Environment environment;

    protected Properties variables = new Properties();
     //类型别名注册表
   protected final TypeAliasRegistry typeAliasRegistry = new TypeAliasRegistry();
   //语言驱动注册表
   protected final LanguageDriverRegistry languageRegistry = new LanguageDriverRegistry();

   这几个重要的属性,特别是Properties variables。因为在XPathParser类中也有这个属性,千万不能搞混了。

    

public class XPathParser {
......
private Properties variables;
......
}

三,明白了Configuration在的大概结构和实例化的时候都做了什么事情之后,我们就接着第一点的末尾继续跟踪代码。

  1,在第一点中我们提到:类XMLConfigBuilder使用super关键字调用了父类BaseBuilder的使用Configuration作为参数的构造方法:
  

  在BaseBuilder中,对新实例化的Configuration 对象进行了赋值,同时对TypeAliasRegistry进行了赋值。

  2,回到XMLConfigBuilder的构造方法

  

  文章开始的地方我们说过 enviroment和props 是null,所以this.configuration.variables == null,this.environment == null。

  this.parsed  =false;意思是还没有执行对configration.xml的解析;

  this.parser = parser;这里要注意,这个parser是XPathParser parse。而上一篇文章 Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 中的 parser 是XMLConfigBuilder类的对象。

      

  到这里实例化xml配置解析器(XMLConfigBuilder)就到此结束了。不要以为XMLConfigBuilder的任务就结束了,no ,no ,no .这才是刚刚开始


原创不易,转载请声明出处:https://www.cnblogs.com/zhangchengzi/p/9673715.html

Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)的更多相关文章

  1. Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码

    在文章:Mybatis源码解析,一步一步从浅入深(一):创建准备工程,中我们为了解析mybatis源码创建了一个mybatis的简单工程(源码已上传github,链接在文章末尾),并实现了一个查询功能 ...

  2. Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例

    在Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们看到了XMLConfigBuilder(xml配置解析器)的实例化.而且这个实例化过程在文章:Mybatis源码解析,一步一步从浅 ...

  3. Mybatis源码解析,一步一步从浅入深(五):mapper节点的解析

    在上一篇文章Mybatis源码解析,一步一步从浅入深(四):将configuration.xml的解析到Configuration对象实例中我们谈到了properties,settings,envir ...

  4. MyBatis 源码分析 - 映射文件解析过程

    1.简介 在上一篇文章中,我详细分析了 MyBatis 配置文件的解析过程.由于上一篇文章的篇幅比较大,加之映射文件解析过程也比较复杂的原因.所以我将映射文件解析过程的分析内容从上一篇文章中抽取出来, ...

  5. Mybatis源码解析,一步一步从浅入深(一):创建准备工程

    Spring SpringMVC Mybatis(简称ssm)是一个很流行的java web框架,而Mybatis作为ORM 持久层框架,因其灵活简单,深受青睐.而且现在的招聘职位中都要求应试者熟悉M ...

  6. Mybatis源码解析,一步一步从浅入深(六):映射代理类的获取

    在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码中我们提到了两个问题: 1,为什么在以前的代码流程中从来没有addMapper,而这里却有getMapper? 2,UserDao ...

  7. Mybatis源码解析,一步一步从浅入深(七):执行查询

    一,前言 我们在文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码的最后一步说到执行查询的关键代码: result = sqlSession.selectOne(command.ge ...

  8. 【MyBatis源码解析】MyBatis一二级缓存

    MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...

  9. Mybatis源码解析-DynamicSqlSource和RawSqlSource的区别

    XMLLanguageDriver是ibatis的默认解析sql节点帮助类,其中的方法其会调用生成DynamicSqlSource和RawSqlSource这两个帮助类,本文将对此作下简单的简析 应用 ...

随机推荐

  1. 2019Hexo博客Next主题深度美化 打造一个炫酷博客(2)-奥怪的小栈

    219/8/1 更新 本文转载于:奥怪的小栈 这篇文章告诉你在搭建好博客后,面对网上千篇一律的美化教程怎么才能添加自己独特点,使人眼前一亮. 本站基于HEXO+Github搭建. 所以你需要准备好HE ...

  2. js设置,取得,清除cookie

    //取得cookie function getCookie(name) {  var nameEQ = name + "=";  var ca = document.cookie. ...

  3. shiro实现session共享(本文转自店蛋蛋)

    session共享:在多应用系统中,如果使用了负载均衡,用户的请求会被分发到不同的应用中,A应用中的session数据在B应用中是获取不到的,就会带来共享的问题. 假设:用户第一次访问,连接的A服务器 ...

  4. n的阶乘尾数有几个0

    /* n!尾数有几个0 */ #include <iostream> using namespace std; void find0(int n); int find(int i,int ...

  5. Spark应用场景以及与hadoop的比较

    一.大数据的四大特征: a.海量的数据规模(volume) b.快速的数据流转和动态的数据体系(velocity) c.多样的数据类型(variety) d.巨大的数据价值(value) 二.Spar ...

  6. Python源码学习Schedule

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  7. unity编辑器扩展_07(创建对话框,检测按钮的点击,点击按钮后提示信息,保存设置的数据,显示点击按钮后的处理的进度条信息)

    代码: using UnityEditor;using UnityEngine; public class ChangeValue : ScriptableWizard {               ...

  8. Java IO体系之File类浅析

    Java IO体系之File类浅析 一.File类介绍 位于java.io下的Java File类以抽象的方式代表文件名和目录路径名.该类主要用于文件和目录的创建.文件的查找和文件的删除等.File对 ...

  9. python decode encode 解码与编码问题

    python 解码与编码问题 1.decode 俗称解码,把编码解码成unicode,例如一个字符串变量 str 是utf-8编码,使用str.decode('utf-8')  ,就是把utf-8编码 ...

  10. C#装箱与拆箱总结

    装箱和拆箱是值类型和引用类型之间相互转换是要执行的操作.  1. 装箱在值类型向引用类型转换时发生 2. 拆箱在引用类型向值类型转换时发生 光上述两句话不难理解,但是往深处了解,就需要一些篇幅来解释了 ...