zoukankan      html  css  js  c++  java
  • Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)

    在上一篇文章: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 

  • 相关阅读:
    hihocoder 1049 后序遍历
    hihocoder 1310 岛屿
    Leetcode 63. Unique Paths II
    Leetcode 62. Unique Paths
    Leetcode 70. Climbing Stairs
    poj 3544 Journey with Pigs
    Leetcode 338. Counting Bits
    Leetcode 136. Single Number
    Leetcode 342. Power of Four
    Leetcode 299. Bulls and Cows
  • 原文地址:https://www.cnblogs.com/zhangchengzi/p/9673715.html
Copyright © 2011-2022 走看看