• 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 

  • 相关阅读:
    学习笔记
    聊聊字节序
    SPDK发送和接收连接请求的处理
    企业设备维护——不仅仅是解决问题
    怎样快速找到某一行代码的git提交记录
    生产环境中利用软链接避免"rm -rf /"的方法
    程序员五年小结
    Django Model 数据库增删改查
    python中字符串列表字典常用方法
    python编辑配置
  • 原文地址:https://www.cnblogs.com/zhangchengzi/p/9673715.html
Copyright © 2020-2023  润新知