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