Mybatis源碼解析,一步一步從淺入深(三):實例化xml配置解析器(XMLConfigBuilder)

 

在上一篇文章:Mybatis源碼解析,一步一步從淺入深(二):按步驟解析源碼 ,中咱們看到html

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

  使用讀取的configuration.xml字符輸入流做爲參數,使用XMLConfigBuilder類的三個參數的構造器實例化一個xml配置解析器(XMLConfigBuilder),而且 environment, properties的值爲null。而且在這個過程當中會實例化一個很是重要的類Configuration的對象。那麼接下來就看一下XMLConfigBuilder的實例化過程ide

一,首先看下這個三個參數的構造器源碼:post

  

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

這裏又經過this關鍵字,調用了XMLConfigBuilder類的另一個三個參數的私有構造方法:ui

  這個構造器的參數XPathParser parser就等於上一個構造器中的new XPathParser(reader, true, props, new XMLMapperEntityResolver());this

  XPathParser 是一個xml解析器,同時reader就是configuration.xml字符輸入流,而props等於null;url

    具體的XPathParser xml解析器的實例化過程就再也不這裏詳細描述了,你們有須要,我再領寫一篇文章。spa

  同時environment, properties的值爲nullcode

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做爲參數的構造方法:xml

  

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 .這纔是剛剛開始

 


 原創不易,轉載請聲明出處:http://www.javashuo.com/article/p-majpapxv-bn.html 

相關文章
相關標籤/搜索